From a047251fda1fd9c11212da0a5bee254e3a888b7c Mon Sep 17 00:00:00 2001 From: "Yashmeet ." Date: Thu, 4 Jun 2026 14:32:28 +0530 Subject: [PATCH 1/8] Move leading app to SDM plugin & workflow files update to read these apps from SDM plugin --- .../workflows/SAPUI5_Version_Monitoring.yml | 10 +- .github/workflows/cfdeploy.yml | 30 +- .github/workflows/multiTenancyDeployLocal.yml | 20 +- ...ultiTenant_deploy_and_Integration_test.yml | 18 +- ...loy_and_Integration_test_LatestVersion.yml | 24 +- ...ngleTenant_deploy_and_Integration_test.yml | 19 +- ...loy_and_Integration_test_LatestVersion.yml | 25 +- .github/workflows/sonarqube.yml | 4 +- .../cloud-cap-samples-java/.cdsprettier.json | 12 + .../cloud-cap-samples-java/.cdsrc.json | 20 + .../.github/workflows/maven.yml | 30 + .../cloud-cap-samples-java/.gitignore | 38 + .../cloud-cap-samples-java/.reuse/dep5 | 29 + .../.tours/sample-tour.tour | 201 + .../cloud-cap-samples-java/LICENSE | 175 + .../LICENSES/Apache-2.0.txt | 208 + .../cloud-cap-samples-java/README.md | 591 +++ .../app/_i18n/i18n.properties | 115 + .../app/_i18n/i18n_de.properties | 71 + .../app/addresses/fiori-service.cds | 83 + .../app/addresses/package.json | 12 + .../app/addresses/webapp/Component.js | 3 + .../app/addresses/webapp/i18n/i18n.properties | 2 + .../addresses/webapp/i18n/i18n_de.properties | 2 + .../app/addresses/webapp/index.html | 35 + .../app/addresses/webapp/manifest.json | 142 + .../app/admin/fiori-service.cds | 401 ++ .../app/admin/package.json | 12 + .../app/admin/webapp/Component.js | 3 + .../books/controller/custom.controller.js | 33 + .../webapp/controller/custom.controller.js | 141 + .../app/admin/webapp/extension/Upload.js | 119 + .../extension/UploadDialog.fragment.xml | 27 + .../webapp/fragments/changelog.fragment.xml | 47 + .../app/admin/webapp/i18n/i18n.properties | 2 + .../app/admin/webapp/i18n/i18n_de.properties | 2 + .../app/admin/webapp/index.html | 35 + .../app/admin/webapp/manifest.json | 487 ++ .../app/appconfig/fioriSandboxConfig.json | 185 + .../app/browse/fiori-service.cds | 177 + .../app/browse/package.json | 12 + .../app/browse/webapp/Component.js | 3 + .../app/browse/webapp/i18n/i18n.properties | 2 + .../app/browse/webapp/i18n/i18n_de.properties | 2 + .../app/browse/webapp/index.html | 35 + .../app/browse/webapp/manifest.json | 142 + .../cloud-cap-samples-java/app/common.cds | 1193 +++++ .../cloud-cap-samples-java/app/fiori.html | 30 + .../cloud-cap-samples-java/app/index.cds | 11 + .../app/notes/fiori-service.cds | 133 + .../app/notes/package.json | 12 + .../app/notes/webapp/Component.js | 3 + .../app/notes/webapp/i18n/i18n.properties | 2 + .../app/notes/webapp/i18n/i18n_de.properties | 2 + .../app/notes/webapp/index.html | 35 + .../app/notes/webapp/manifest.json | 120 + .../app/orders/fiori-service.cds | 293 ++ .../app/orders/package.json | 12 + .../app/orders/webapp/Component.js | 3 + .../app/orders/webapp/i18n/i18n.properties | 2 + .../app/orders/webapp/i18n/i18n_de.properties | 2 + .../app/orders/webapp/index.html | 35 + .../app/orders/webapp/manifest.json | 184 + .../app/package-lock.json | 2014 +++++++++ .../cloud-cap-samples-java/app/package.json | 9 + .../app/reviews/fiori-service.cds | 90 + .../app/reviews/package.json | 12 + .../app/reviews/webapp/Component.js | 3 + .../app/reviews/webapp/i18n/i18n.properties | 2 + .../reviews/webapp/i18n/i18n_de.properties | 2 + .../app/reviews/webapp/index.html | 35 + .../app/reviews/webapp/manifest.json | 142 + .../cloud-cap-samples-java/app/vue/app.js | 122 + .../cloud-cap-samples-java/app/vue/index.html | 104 + .../cloud-cap-samples-java/app/xs-app.json | 78 + .../cloud-cap-samples-java/assets/books.csv | 6 + .../assets/readmeImages/BookPage.png | Bin 0 -> 211617 bytes .../assets/readmeImages/FioriHome.png | Bin 0 -> 55710 bytes .../assets/readmeImages/core-concepts.png | Bin 0 -> 116291 bytes .../cloud-cap-samples-java/db/books.cds | 96 + .../cloud-cap-samples-java/db/common.cds | 10 + ...INESS_PARTNER-A_BusinessPartnerAddress.csv | 6 + .../db/data/Statuses.csv | 6 + .../db/data/Statuses_text.csv | 6 + .../db/data/WDIRICodeList.csv | 4 + .../db/data/WDIRSCodeList.csv | 4 + .../db/data/my.bookshop-Authors.csv | 10 + .../db/data/my.bookshop-Books.csv | 6 + .../db/data/my.bookshop-Books.texts.csv | 5 + .../db/data/my.bookshop-Genres.csv | 16 + .../db/data/my.bookshop-Notes.csv | 4 + .../db/data/my.bookshop-OrderItems.csv | 4 + .../db/data/my.bookshop-Orders.csv | 3 + .../db/data/my.bookshop-Reviews.csv | 25 + .../data/sap.attachments-UploadScanStates.csv | 6 + .../db/data/sap.common-Currencies.csv | 7 + .../db/data/sap.common-Currencies.texts.csv | 13 + .../db/data/sap.common-Languages.csv | 7 + .../db/data/sap.common-Languages.texts.csv | 19 + .../cloud-cap-samples-java/db/index.cds | 6 + .../cloud-cap-samples-java/db/notes.cds | 7 + .../cloud-cap-samples-java/db/orders.cds | 25 + .../db/package-lock.json | 179 + .../cloud-cap-samples-java/db/package.json | 13 + .../cloud-cap-samples-java/db/pom.xml | 47 + .../cloud-cap-samples-java/db/repository.cds | 11 + .../cloud-cap-samples-java/db/reviews.cds | 31 + .../fts/isbn/schema.cds | 31 + .../integration-tests/pom.xml | 135 + .../java/my/bookshop/it/FeatureTogglesIT.java | 58 + .../mta-single-tenant.yaml | 95 + .../mtx/sidecar/package.json | 25 + .../cloud-cap-samples-java/package.json | 13 + .../cloud-cap-samples-java/pom.xml | 171 + .../cloud-cap-samples-java/requests.http | 16 + .../create-container-registry-secret.sh | 28 + .../scripts/create-db-secret.sh | 78 + .../scripts/create-sm-secret.sh | 96 + .../scripts/format-kyma-secret.js | 9 + .../cloud-cap-samples-java/scripts/value.js | 38 + .../srv/admin-service.cds | 376 ++ .../srv/attachment-extension.cds | 155 + .../srv/cat-service.cds | 34 + .../cloud-cap-samples-java/srv/external.cds | 40 + .../srv/external/API_BUSINESS_PARTNER.cds | 3977 +++++++++++++++++ .../srv/external/API_BUSINESS_PARTNER.edmx | 3376 ++++++++++++++ .../srv/notes-mashup.cds | 32 + .../srv/notes-service.cds | 6 + .../cloud-cap-samples-java/srv/pom.xml | 284 ++ .../srv/review-service.cds | 30 + .../main/java/my/bookshop/Application.java | 29 + .../main/java/my/bookshop/MessageKeys.java | 19 + .../java/my/bookshop/RatingCalculator.java | 64 + .../config/CustomFeatureToggleProvider.java | 30 + .../config/DestinationConfiguration.java | 37 + .../config/SwaggerResourceConfig.java | 14 + .../my/bookshop/config/WebSecurityConfig.java | 25 + .../handlers/AdminServiceAddressHandler.java | 154 + .../handlers/AdminServiceAuditHandler.java | 144 + .../handlers/AdminServiceHandler.java | 456 ++ .../handlers/BookRatingInitialization.java | 31 + .../handlers/CatalogServiceHandler.java | 194 + .../my/bookshop/handlers/DependencyExit.java | 104 + .../handlers/NotesServiceHandler.java | 208 + .../bookshop/handlers/OnboardRepository.java | 14 + .../java/my/bookshop/handlers/Repository.java | 36 + .../handlers/SubscriptionHandler.java | 33 + .../ApiBusinessPartnerEventMockHandler.java | 50 + .../java/my/bookshop/health/AppActuator.java | 27 + .../health/CustomHealthIndicator.java | 28 + .../native-image/resource-config.json | 12 + .../srv/src/main/resources/application.yaml | 136 + .../srv/src/main/resources/logback-spring.xml | 16 + .../src/main/resources/messages.properties | 14 + .../src/main/resources/messages_de.properties | 13 + .../srv/src/main/resources/schema-nomocks.sql | 1270 ++++++ .../srv/src/main/resources/schema.sql | 1963 ++++++++ .../srv/src/main/resources/swagger/index.html | 93 + .../AdminServiceAddressITestBase.java | 114 + .../AdminServiceAddress_default_ITest.java | 29 + .../AdminServiceAddress_mocked_ITest.java | 30 + .../java/my/bookshop/AdminServiceTest.java | 96 + .../java/my/bookshop/CatalogServiceITest.java | 93 + .../java/my/bookshop/CatalogServiceTest.java | 138 + .../java/my/bookshop/NotesServiceITest.java | 192 + .../my/bookshop/RatingCalculatorTest.java | 37 + .../handlers/CatalogServiceHandlerTest.java | 30 + .../native-image/native-image.properties | 1 + .../META-INF/native-image/reflect-config.json | 6 + .../srv/user-service.cds | 10 + .../xs-security-mt.json | 37 + .../cloud-cap-samples-java/xs-security.json | 18 + .../cloud-cap-samples-java/.cdsprettier.json | 12 + .../cloud-cap-samples-java/.cdsrc.json | 20 + .../.github/workflows/maven.yml | 30 + .../cloud-cap-samples-java/.gitignore | 38 + .../cloud-cap-samples-java/.reuse/dep5 | 29 + .../.tours/sample-tour.tour | 201 + .../cloud-cap-samples-java/LICENSE | 175 + .../LICENSES/Apache-2.0.txt | 208 + .../cloud-cap-samples-java/README.md | 591 +++ .../app/_i18n/i18n.properties | 115 + .../app/_i18n/i18n_de.properties | 71 + .../app/addresses/fiori-service.cds | 83 + .../app/addresses/package.json | 12 + .../app/addresses/webapp/Component.js | 3 + .../app/addresses/webapp/i18n/i18n.properties | 2 + .../addresses/webapp/i18n/i18n_de.properties | 2 + .../app/addresses/webapp/index.html | 35 + .../app/addresses/webapp/manifest.json | 142 + .../app/admin/fiori-service.cds | 401 ++ .../app/admin/package.json | 12 + .../app/admin/webapp/Component.js | 3 + .../books/controller/custom.controller.js | 33 + .../webapp/controller/custom.controller.js | 141 + .../app/admin/webapp/extension/Upload.js | 119 + .../extension/UploadDialog.fragment.xml | 27 + .../webapp/fragments/changelog.fragment.xml | 47 + .../app/admin/webapp/i18n/i18n.properties | 2 + .../app/admin/webapp/i18n/i18n_de.properties | 2 + .../app/admin/webapp/index.html | 35 + .../app/admin/webapp/manifest.json | 487 ++ .../app/appconfig/fioriSandboxConfig.json | 185 + .../app/browse/fiori-service.cds | 177 + .../app/browse/package.json | 12 + .../app/browse/webapp/Component.js | 3 + .../app/browse/webapp/i18n/i18n.properties | 2 + .../app/browse/webapp/i18n/i18n_de.properties | 2 + .../app/browse/webapp/index.html | 35 + .../app/browse/webapp/manifest.json | 142 + .../cloud-cap-samples-java/app/common.cds | 1193 +++++ .../cloud-cap-samples-java/app/fiori.html | 30 + .../cloud-cap-samples-java/app/index.cds | 11 + .../app/notes/fiori-service.cds | 133 + .../app/notes/package.json | 12 + .../app/notes/webapp/Component.js | 3 + .../app/notes/webapp/i18n/i18n.properties | 2 + .../app/notes/webapp/i18n/i18n_de.properties | 2 + .../app/notes/webapp/index.html | 35 + .../app/notes/webapp/manifest.json | 120 + .../app/orders/fiori-service.cds | 293 ++ .../app/orders/package.json | 12 + .../app/orders/webapp/Component.js | 3 + .../app/orders/webapp/i18n/i18n.properties | 2 + .../app/orders/webapp/i18n/i18n_de.properties | 2 + .../app/orders/webapp/index.html | 35 + .../app/orders/webapp/manifest.json | 184 + .../app/package-lock.json | 2014 +++++++++ .../cloud-cap-samples-java/app/package.json | 9 + .../app/reviews/fiori-service.cds | 90 + .../app/reviews/package.json | 12 + .../app/reviews/webapp/Component.js | 3 + .../app/reviews/webapp/i18n/i18n.properties | 2 + .../reviews/webapp/i18n/i18n_de.properties | 2 + .../app/reviews/webapp/index.html | 35 + .../app/reviews/webapp/manifest.json | 142 + .../cloud-cap-samples-java/app/vue/app.js | 122 + .../cloud-cap-samples-java/app/vue/index.html | 104 + .../cloud-cap-samples-java/app/xs-app.json | 78 + .../cloud-cap-samples-java/assets/books.csv | 6 + .../assets/readmeImages/BookPage.png | Bin 0 -> 211617 bytes .../assets/readmeImages/FioriHome.png | Bin 0 -> 55710 bytes .../assets/readmeImages/core-concepts.png | Bin 0 -> 116291 bytes .../cloud-cap-samples-java/db/books.cds | 96 + .../cloud-cap-samples-java/db/common.cds | 10 + ...INESS_PARTNER-A_BusinessPartnerAddress.csv | 6 + .../db/data/Statuses.csv | 6 + .../db/data/Statuses_text.csv | 6 + .../db/data/WDIRICodeList.csv | 4 + .../db/data/WDIRSCodeList.csv | 4 + .../db/data/my.bookshop-Authors.csv | 10 + .../db/data/my.bookshop-Books.csv | 6 + .../db/data/my.bookshop-Books.texts.csv | 5 + .../db/data/my.bookshop-Genres.csv | 16 + .../db/data/my.bookshop-Notes.csv | 4 + .../db/data/my.bookshop-OrderItems.csv | 4 + .../db/data/my.bookshop-Orders.csv | 3 + .../db/data/my.bookshop-Reviews.csv | 25 + .../data/sap.attachments-UploadScanStates.csv | 6 + .../db/data/sap.common-Currencies.csv | 7 + .../db/data/sap.common-Currencies.texts.csv | 13 + .../db/data/sap.common-Languages.csv | 7 + .../db/data/sap.common-Languages.texts.csv | 19 + .../cloud-cap-samples-java/db/index.cds | 6 + .../cloud-cap-samples-java/db/notes.cds | 7 + .../cloud-cap-samples-java/db/orders.cds | 25 + .../db/package-lock.json | 179 + .../cloud-cap-samples-java/db/package.json | 13 + .../cloud-cap-samples-java/db/pom.xml | 47 + .../cloud-cap-samples-java/db/repository.cds | 11 + .../cloud-cap-samples-java/db/reviews.cds | 31 + .../fts/isbn/schema.cds | 31 + .../integration-tests/pom.xml | 135 + .../java/my/bookshop/it/FeatureTogglesIT.java | 58 + .../mta-single-tenant.yaml | 95 + .../mtx/sidecar/package.json | 25 + .../cloud-cap-samples-java/package.json | 13 + .../cloud-cap-samples-java/pom.xml | 171 + .../cloud-cap-samples-java/requests.http | 16 + .../create-container-registry-secret.sh | 28 + .../scripts/create-db-secret.sh | 78 + .../scripts/create-sm-secret.sh | 96 + .../scripts/format-kyma-secret.js | 9 + .../cloud-cap-samples-java/scripts/value.js | 38 + .../srv/admin-service.cds | 376 ++ .../srv/attachment-extension.cds | 155 + .../srv/cat-service.cds | 34 + .../cloud-cap-samples-java/srv/external.cds | 40 + .../srv/external/API_BUSINESS_PARTNER.cds | 3977 +++++++++++++++++ .../srv/external/API_BUSINESS_PARTNER.edmx | 3376 ++++++++++++++ .../srv/notes-mashup.cds | 32 + .../srv/notes-service.cds | 6 + .../cloud-cap-samples-java/srv/pom.xml | 284 ++ .../srv/review-service.cds | 30 + .../main/java/my/bookshop/Application.java | 29 + .../main/java/my/bookshop/MessageKeys.java | 19 + .../java/my/bookshop/RatingCalculator.java | 64 + .../config/CustomFeatureToggleProvider.java | 30 + .../config/DestinationConfiguration.java | 37 + .../config/SwaggerResourceConfig.java | 14 + .../my/bookshop/config/WebSecurityConfig.java | 25 + .../handlers/AdminServiceAddressHandler.java | 154 + .../handlers/AdminServiceAuditHandler.java | 144 + .../handlers/AdminServiceHandler.java | 456 ++ .../handlers/BookRatingInitialization.java | 31 + .../handlers/CatalogServiceHandler.java | 194 + .../my/bookshop/handlers/DependencyExit.java | 104 + .../handlers/NotesServiceHandler.java | 208 + .../bookshop/handlers/OnboardRepository.java | 14 + .../java/my/bookshop/handlers/Repository.java | 36 + .../handlers/SubscriptionHandler.java | 33 + .../ApiBusinessPartnerEventMockHandler.java | 50 + .../java/my/bookshop/health/AppActuator.java | 27 + .../health/CustomHealthIndicator.java | 28 + .../native-image/resource-config.json | 12 + .../srv/src/main/resources/application.yaml | 136 + .../srv/src/main/resources/logback-spring.xml | 16 + .../src/main/resources/messages.properties | 14 + .../src/main/resources/messages_de.properties | 13 + .../srv/src/main/resources/schema-nomocks.sql | 1270 ++++++ .../srv/src/main/resources/schema.sql | 1963 ++++++++ .../srv/src/main/resources/swagger/index.html | 93 + .../AdminServiceAddressITestBase.java | 114 + .../AdminServiceAddress_default_ITest.java | 29 + .../AdminServiceAddress_mocked_ITest.java | 30 + .../java/my/bookshop/AdminServiceTest.java | 96 + .../java/my/bookshop/CatalogServiceITest.java | 93 + .../java/my/bookshop/CatalogServiceTest.java | 138 + .../java/my/bookshop/NotesServiceITest.java | 192 + .../my/bookshop/RatingCalculatorTest.java | 37 + .../handlers/CatalogServiceHandlerTest.java | 30 + .../native-image/native-image.properties | 1 + .../META-INF/native-image/reflect-config.json | 6 + .../srv/user-service.cds | 10 + .../xs-security-mt.json | 37 + .../cloud-cap-samples-java/xs-security.json | 18 + .../central-space/attachments-demo-app.capnb | 244 + .../central-space/demoapp/.cdsrc.json | 5 + .../central-space/demoapp/.gitignore | 31 + .../demoapp/app/_i18n/i18n.properties | 66 + .../demoapp/app/_i18n/i18n_de.properties | 51 + .../demoapp/app/admin-books/fiori-service.cds | 375 ++ .../demoapp/app/admin-books/package.json | 13 + .../app/admin-books/webapp/Component.js | 8 + .../webapp/controller/custom.controller.js | 141 + .../webapp/fragments/changelog.fragment.xml | 47 + .../admin-books/webapp/i18n/i18n.properties | 3 + .../webapp/i18n/i18n_de.properties | 3 + .../app/admin-books/webapp/manifest.json | 477 ++ .../app/appconfig/fioriSandboxConfig.json | 95 + .../demoapp/app/browse/fiori-service.cds | 56 + .../demoapp/app/browse/webapp/Component.js | 7 + .../app/browse/webapp/i18n/i18n.properties | 3 + .../app/browse/webapp/i18n/i18n_de.properties | 3 + .../demoapp/app/browse/webapp/manifest.json | 138 + .../central-space/demoapp/app/common.cds | 1070 +++++ .../central-space/demoapp/app/index.html | 32 + .../central-space/demoapp/app/package.json | 9 + .../central-space/demoapp/app/services.cds | 6 + .../central-space/demoapp/app/xs-app.json | 85 + .../demoapp/db/data/WDIRSCodeList.csv | 4 + .../data/sap.attachments-UploadScanStates.csv | 6 + .../db/data/sap.capire.bookshop-Authors.csv | 5 + .../db/data/sap.capire.bookshop-Books.csv | 6 + .../data/sap.capire.bookshop-Books_texts.csv | 5 + .../db/data/sap.capire.bookshop-Genres.csv | 16 + .../demoapp/db/package-lock.json | 325 ++ .../central-space/demoapp/db/package.json | 15 + .../central-space/demoapp/db/pom.xml | 47 + .../central-space/demoapp/db/schema.cds | 98 + .../central-space/demoapp/mta.yaml | 110 + .../central-space/demoapp/package-lock.json | 13 + .../central-space/demoapp/package.json | 11 + .../central-space/demoapp/pom.xml | 149 + .../demoapp/srv/admin-service.cds | 322 ++ .../demoapp/srv/attachment-extension.cds | 168 + .../central-space/demoapp/srv/cat-service.cds | 34 + .../central-space/demoapp/srv/pom.xml | 170 + .../java/customer/demoapp/Application.java | 13 + .../demoapp/handlers/AdminServiceHandler.java | 230 + .../handlers/CatalogServiceHandler.java | 63 + .../srv/src/main/resources/application.yaml | 11 + .../src/main/resources/messages.properties | 1 + .../handlers/CatalogServiceHandlerTest.java | 42 + .../demoapp/srv/user-service.cds | 10 + .../central-space/demoapp/xs-security.json | 18 + .../personal-space/attachments-demo-app.capnb | 244 + .../personal-space/demoapp/.cdsrc.json | 5 + .../personal-space/demoapp/.gitignore | 31 + .../demoapp/app/_i18n/i18n.properties | 66 + .../demoapp/app/_i18n/i18n_de.properties | 51 + .../demoapp/app/admin-books/fiori-service.cds | 375 ++ .../demoapp/app/admin-books/package.json | 13 + .../app/admin-books/webapp/Component.js | 8 + .../webapp/controller/custom.controller.js | 141 + .../webapp/fragments/changelog.fragment.xml | 47 + .../admin-books/webapp/i18n/i18n.properties | 3 + .../webapp/i18n/i18n_de.properties | 3 + .../app/admin-books/webapp/manifest.json | 477 ++ .../app/appconfig/fioriSandboxConfig.json | 95 + .../demoapp/app/browse/fiori-service.cds | 56 + .../demoapp/app/browse/webapp/Component.js | 7 + .../app/browse/webapp/i18n/i18n.properties | 3 + .../app/browse/webapp/i18n/i18n_de.properties | 3 + .../demoapp/app/browse/webapp/manifest.json | 138 + .../personal-space/demoapp/app/common.cds | 1070 +++++ .../personal-space/demoapp/app/index.html | 32 + .../personal-space/demoapp/app/package.json | 9 + .../personal-space/demoapp/app/services.cds | 6 + .../personal-space/demoapp/app/xs-app.json | 85 + .../demoapp/db/data/WDIRSCodeList.csv | 4 + .../data/sap.attachments-UploadScanStates.csv | 6 + .../db/data/sap.capire.bookshop-Authors.csv | 5 + .../db/data/sap.capire.bookshop-Books.csv | 6 + .../data/sap.capire.bookshop-Books_texts.csv | 5 + .../db/data/sap.capire.bookshop-Genres.csv | 16 + .../demoapp/db/package-lock.json | 325 ++ .../personal-space/demoapp/db/package.json | 15 + .../personal-space/demoapp/db/pom.xml | 47 + .../personal-space/demoapp/db/schema.cds | 98 + .../personal-space/demoapp/mta.yaml | 110 + .../personal-space/demoapp/package-lock.json | 13 + .../personal-space/demoapp/package.json | 11 + .../personal-space/demoapp/pom.xml | 149 + .../demoapp/srv/admin-service.cds | 321 ++ .../demoapp/srv/attachment-extension.cds | 168 + .../demoapp/srv/cat-service.cds | 34 + .../personal-space/demoapp/srv/pom.xml | 170 + .../java/customer/demoapp/Application.java | 13 + .../demoapp/handlers/AdminServiceHandler.java | 230 + .../handlers/CatalogServiceHandler.java | 63 + .../srv/src/main/resources/application.yaml | 11 + .../src/main/resources/messages.properties | 1 + .../handlers/CatalogServiceHandlerTest.java | 42 + .../demoapp/srv/user-service.cds | 10 + .../personal-space/demoapp/xs-security.json | 18 + 436 files changed, 57879 insertions(+), 92 deletions(-) create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/.cdsprettier.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/.cdsrc.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/.github/workflows/maven.yml create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/.gitignore create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/.reuse/dep5 create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/.tours/sample-tour.tour create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/LICENSE create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/LICENSES/Apache-2.0.txt create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/README.md create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/_i18n/i18n.properties create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/_i18n/i18n_de.properties create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/fiori-service.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/package.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/webapp/Component.js create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/webapp/i18n/i18n.properties create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/webapp/i18n/i18n_de.properties create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/webapp/index.html create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/webapp/manifest.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/fiori-service.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/package.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/Component.js create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/books/controller/custom.controller.js create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/controller/custom.controller.js create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/extension/Upload.js create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/extension/UploadDialog.fragment.xml create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/fragments/changelog.fragment.xml create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/i18n/i18n.properties create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/i18n/i18n_de.properties create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/index.html create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/manifest.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/appconfig/fioriSandboxConfig.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/fiori-service.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/package.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/webapp/Component.js create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/webapp/i18n/i18n.properties create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/webapp/i18n/i18n_de.properties create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/webapp/index.html create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/webapp/manifest.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/common.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/fiori.html create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/index.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/fiori-service.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/package.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/webapp/Component.js create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/webapp/i18n/i18n.properties create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/webapp/i18n/i18n_de.properties create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/webapp/index.html create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/webapp/manifest.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/fiori-service.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/package.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/webapp/Component.js create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/webapp/i18n/i18n.properties create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/webapp/i18n/i18n_de.properties create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/webapp/index.html create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/webapp/manifest.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/package-lock.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/package.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/fiori-service.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/package.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/webapp/Component.js create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/webapp/i18n/i18n.properties create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/webapp/i18n/i18n_de.properties create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/webapp/index.html create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/webapp/manifest.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/vue/app.js create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/vue/index.html create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/app/xs-app.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/assets/books.csv create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/assets/readmeImages/BookPage.png create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/assets/readmeImages/FioriHome.png create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/assets/readmeImages/core-concepts.png create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/books.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/common.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/data/API_BUSINESS_PARTNER-A_BusinessPartnerAddress.csv create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/data/Statuses.csv create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/data/Statuses_text.csv create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/data/WDIRICodeList.csv create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/data/WDIRSCodeList.csv create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Authors.csv create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Books.csv create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Books.texts.csv create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Genres.csv create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Notes.csv create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-OrderItems.csv create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Orders.csv create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Reviews.csv create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/data/sap.attachments-UploadScanStates.csv create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/data/sap.common-Currencies.csv create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/data/sap.common-Currencies.texts.csv create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/data/sap.common-Languages.csv create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/data/sap.common-Languages.texts.csv create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/index.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/notes.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/orders.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/package-lock.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/package.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/pom.xml create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/repository.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/db/reviews.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/fts/isbn/schema.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/integration-tests/pom.xml create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/integration-tests/src/test/java/my/bookshop/it/FeatureTogglesIT.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/mta-single-tenant.yaml create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/mtx/sidecar/package.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/package.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/pom.xml create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/requests.http create mode 100755 app/multi-tenant/central-space/cloud-cap-samples-java/scripts/create-container-registry-secret.sh create mode 100755 app/multi-tenant/central-space/cloud-cap-samples-java/scripts/create-db-secret.sh create mode 100755 app/multi-tenant/central-space/cloud-cap-samples-java/scripts/create-sm-secret.sh create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/scripts/format-kyma-secret.js create mode 100755 app/multi-tenant/central-space/cloud-cap-samples-java/scripts/value.js create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/admin-service.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/attachment-extension.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/cat-service.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/external.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/external/API_BUSINESS_PARTNER.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/external/API_BUSINESS_PARTNER.edmx create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/notes-mashup.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/notes-service.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/pom.xml create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/review-service.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/Application.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/MessageKeys.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/RatingCalculator.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/CustomFeatureToggleProvider.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/DestinationConfiguration.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/SwaggerResourceConfig.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/WebSecurityConfig.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceAddressHandler.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceAuditHandler.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceHandler.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/BookRatingInitialization.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/CatalogServiceHandler.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/DependencyExit.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/NotesServiceHandler.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/OnboardRepository.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/Repository.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/SubscriptionHandler.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/external/ApiBusinessPartnerEventMockHandler.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/health/AppActuator.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/health/CustomHealthIndicator.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/META-INF/native-image/resource-config.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/application.yaml create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/logback-spring.xml create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/messages.properties create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/messages_de.properties create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/schema-nomocks.sql create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/schema.sql create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/swagger/index.html create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddressITestBase.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddress_default_ITest.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddress_mocked_ITest.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceTest.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/CatalogServiceITest.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/CatalogServiceTest.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/NotesServiceITest.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/RatingCalculatorTest.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/handlers/CatalogServiceHandlerTest.java create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/resources/META-INF/native-image/native-image.properties create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/resources/META-INF/native-image/reflect-config.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/srv/user-service.cds create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/xs-security-mt.json create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/xs-security.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/.cdsprettier.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/.cdsrc.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/.github/workflows/maven.yml create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/.gitignore create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/.reuse/dep5 create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/.tours/sample-tour.tour create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/LICENSE create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/LICENSES/Apache-2.0.txt create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/README.md create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/_i18n/i18n.properties create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/_i18n/i18n_de.properties create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/fiori-service.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/package.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/webapp/Component.js create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/webapp/i18n/i18n.properties create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/webapp/i18n/i18n_de.properties create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/webapp/index.html create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/webapp/manifest.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/fiori-service.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/package.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/Component.js create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/books/controller/custom.controller.js create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/controller/custom.controller.js create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/extension/Upload.js create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/extension/UploadDialog.fragment.xml create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/fragments/changelog.fragment.xml create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/i18n/i18n.properties create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/i18n/i18n_de.properties create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/index.html create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/manifest.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/appconfig/fioriSandboxConfig.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/fiori-service.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/package.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/webapp/Component.js create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/webapp/i18n/i18n.properties create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/webapp/i18n/i18n_de.properties create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/webapp/index.html create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/webapp/manifest.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/common.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/fiori.html create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/index.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/fiori-service.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/package.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/webapp/Component.js create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/webapp/i18n/i18n.properties create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/webapp/i18n/i18n_de.properties create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/webapp/index.html create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/webapp/manifest.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/fiori-service.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/package.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/webapp/Component.js create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/webapp/i18n/i18n.properties create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/webapp/i18n/i18n_de.properties create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/webapp/index.html create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/webapp/manifest.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/package-lock.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/package.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/fiori-service.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/package.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/webapp/Component.js create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/webapp/i18n/i18n.properties create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/webapp/i18n/i18n_de.properties create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/webapp/index.html create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/webapp/manifest.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/vue/app.js create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/vue/index.html create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/app/xs-app.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/assets/books.csv create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/assets/readmeImages/BookPage.png create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/assets/readmeImages/FioriHome.png create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/assets/readmeImages/core-concepts.png create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/books.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/common.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/API_BUSINESS_PARTNER-A_BusinessPartnerAddress.csv create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/Statuses.csv create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/Statuses_text.csv create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/WDIRICodeList.csv create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/WDIRSCodeList.csv create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Authors.csv create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Books.csv create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Books.texts.csv create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Genres.csv create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Notes.csv create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-OrderItems.csv create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Orders.csv create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Reviews.csv create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/sap.attachments-UploadScanStates.csv create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/sap.common-Currencies.csv create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/sap.common-Currencies.texts.csv create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/sap.common-Languages.csv create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/sap.common-Languages.texts.csv create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/index.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/notes.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/orders.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/package-lock.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/package.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/pom.xml create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/repository.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/db/reviews.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/fts/isbn/schema.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/integration-tests/pom.xml create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/integration-tests/src/test/java/my/bookshop/it/FeatureTogglesIT.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/mta-single-tenant.yaml create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/mtx/sidecar/package.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/package.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/pom.xml create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/requests.http create mode 100755 app/multi-tenant/personal-space/cloud-cap-samples-java/scripts/create-container-registry-secret.sh create mode 100755 app/multi-tenant/personal-space/cloud-cap-samples-java/scripts/create-db-secret.sh create mode 100755 app/multi-tenant/personal-space/cloud-cap-samples-java/scripts/create-sm-secret.sh create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/scripts/format-kyma-secret.js create mode 100755 app/multi-tenant/personal-space/cloud-cap-samples-java/scripts/value.js create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/admin-service.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/attachment-extension.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/cat-service.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/external.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/external/API_BUSINESS_PARTNER.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/external/API_BUSINESS_PARTNER.edmx create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/notes-mashup.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/notes-service.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/pom.xml create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/review-service.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/Application.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/MessageKeys.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/RatingCalculator.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/CustomFeatureToggleProvider.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/DestinationConfiguration.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/SwaggerResourceConfig.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/WebSecurityConfig.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceAddressHandler.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceAuditHandler.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceHandler.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/BookRatingInitialization.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/CatalogServiceHandler.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/DependencyExit.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/NotesServiceHandler.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/OnboardRepository.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/Repository.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/SubscriptionHandler.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/external/ApiBusinessPartnerEventMockHandler.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/health/AppActuator.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/health/CustomHealthIndicator.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/META-INF/native-image/resource-config.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/application.yaml create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/logback-spring.xml create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/messages.properties create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/messages_de.properties create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/schema-nomocks.sql create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/schema.sql create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/swagger/index.html create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddressITestBase.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddress_default_ITest.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddress_mocked_ITest.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceTest.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/CatalogServiceITest.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/CatalogServiceTest.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/NotesServiceITest.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/RatingCalculatorTest.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/handlers/CatalogServiceHandlerTest.java create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/resources/META-INF/native-image/native-image.properties create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/resources/META-INF/native-image/reflect-config.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/srv/user-service.cds create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/xs-security-mt.json create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/xs-security.json create mode 100644 app/single-tenant/central-space/attachments-demo-app.capnb create mode 100644 app/single-tenant/central-space/demoapp/.cdsrc.json create mode 100644 app/single-tenant/central-space/demoapp/.gitignore create mode 100644 app/single-tenant/central-space/demoapp/app/_i18n/i18n.properties create mode 100644 app/single-tenant/central-space/demoapp/app/_i18n/i18n_de.properties create mode 100644 app/single-tenant/central-space/demoapp/app/admin-books/fiori-service.cds create mode 100644 app/single-tenant/central-space/demoapp/app/admin-books/package.json create mode 100644 app/single-tenant/central-space/demoapp/app/admin-books/webapp/Component.js create mode 100644 app/single-tenant/central-space/demoapp/app/admin-books/webapp/controller/custom.controller.js create mode 100644 app/single-tenant/central-space/demoapp/app/admin-books/webapp/fragments/changelog.fragment.xml create mode 100644 app/single-tenant/central-space/demoapp/app/admin-books/webapp/i18n/i18n.properties create mode 100644 app/single-tenant/central-space/demoapp/app/admin-books/webapp/i18n/i18n_de.properties create mode 100644 app/single-tenant/central-space/demoapp/app/admin-books/webapp/manifest.json create mode 100644 app/single-tenant/central-space/demoapp/app/appconfig/fioriSandboxConfig.json create mode 100644 app/single-tenant/central-space/demoapp/app/browse/fiori-service.cds create mode 100644 app/single-tenant/central-space/demoapp/app/browse/webapp/Component.js create mode 100644 app/single-tenant/central-space/demoapp/app/browse/webapp/i18n/i18n.properties create mode 100644 app/single-tenant/central-space/demoapp/app/browse/webapp/i18n/i18n_de.properties create mode 100644 app/single-tenant/central-space/demoapp/app/browse/webapp/manifest.json create mode 100644 app/single-tenant/central-space/demoapp/app/common.cds create mode 100644 app/single-tenant/central-space/demoapp/app/index.html create mode 100644 app/single-tenant/central-space/demoapp/app/package.json create mode 100644 app/single-tenant/central-space/demoapp/app/services.cds create mode 100644 app/single-tenant/central-space/demoapp/app/xs-app.json create mode 100644 app/single-tenant/central-space/demoapp/db/data/WDIRSCodeList.csv create mode 100644 app/single-tenant/central-space/demoapp/db/data/sap.attachments-UploadScanStates.csv create mode 100644 app/single-tenant/central-space/demoapp/db/data/sap.capire.bookshop-Authors.csv create mode 100644 app/single-tenant/central-space/demoapp/db/data/sap.capire.bookshop-Books.csv create mode 100644 app/single-tenant/central-space/demoapp/db/data/sap.capire.bookshop-Books_texts.csv create mode 100644 app/single-tenant/central-space/demoapp/db/data/sap.capire.bookshop-Genres.csv create mode 100644 app/single-tenant/central-space/demoapp/db/package-lock.json create mode 100644 app/single-tenant/central-space/demoapp/db/package.json create mode 100644 app/single-tenant/central-space/demoapp/db/pom.xml create mode 100644 app/single-tenant/central-space/demoapp/db/schema.cds create mode 100644 app/single-tenant/central-space/demoapp/mta.yaml create mode 100644 app/single-tenant/central-space/demoapp/package-lock.json create mode 100644 app/single-tenant/central-space/demoapp/package.json create mode 100644 app/single-tenant/central-space/demoapp/pom.xml create mode 100644 app/single-tenant/central-space/demoapp/srv/admin-service.cds create mode 100644 app/single-tenant/central-space/demoapp/srv/attachment-extension.cds create mode 100644 app/single-tenant/central-space/demoapp/srv/cat-service.cds create mode 100644 app/single-tenant/central-space/demoapp/srv/pom.xml create mode 100644 app/single-tenant/central-space/demoapp/srv/src/main/java/customer/demoapp/Application.java create mode 100644 app/single-tenant/central-space/demoapp/srv/src/main/java/customer/demoapp/handlers/AdminServiceHandler.java create mode 100644 app/single-tenant/central-space/demoapp/srv/src/main/java/customer/demoapp/handlers/CatalogServiceHandler.java create mode 100644 app/single-tenant/central-space/demoapp/srv/src/main/resources/application.yaml create mode 100644 app/single-tenant/central-space/demoapp/srv/src/main/resources/messages.properties create mode 100644 app/single-tenant/central-space/demoapp/srv/src/test/java/customer/demoapp/handlers/CatalogServiceHandlerTest.java create mode 100644 app/single-tenant/central-space/demoapp/srv/user-service.cds create mode 100644 app/single-tenant/central-space/demoapp/xs-security.json create mode 100644 app/single-tenant/personal-space/attachments-demo-app.capnb create mode 100644 app/single-tenant/personal-space/demoapp/.cdsrc.json create mode 100644 app/single-tenant/personal-space/demoapp/.gitignore create mode 100644 app/single-tenant/personal-space/demoapp/app/_i18n/i18n.properties create mode 100644 app/single-tenant/personal-space/demoapp/app/_i18n/i18n_de.properties create mode 100644 app/single-tenant/personal-space/demoapp/app/admin-books/fiori-service.cds create mode 100644 app/single-tenant/personal-space/demoapp/app/admin-books/package.json create mode 100644 app/single-tenant/personal-space/demoapp/app/admin-books/webapp/Component.js create mode 100644 app/single-tenant/personal-space/demoapp/app/admin-books/webapp/controller/custom.controller.js create mode 100644 app/single-tenant/personal-space/demoapp/app/admin-books/webapp/fragments/changelog.fragment.xml create mode 100644 app/single-tenant/personal-space/demoapp/app/admin-books/webapp/i18n/i18n.properties create mode 100644 app/single-tenant/personal-space/demoapp/app/admin-books/webapp/i18n/i18n_de.properties create mode 100644 app/single-tenant/personal-space/demoapp/app/admin-books/webapp/manifest.json create mode 100644 app/single-tenant/personal-space/demoapp/app/appconfig/fioriSandboxConfig.json create mode 100644 app/single-tenant/personal-space/demoapp/app/browse/fiori-service.cds create mode 100644 app/single-tenant/personal-space/demoapp/app/browse/webapp/Component.js create mode 100644 app/single-tenant/personal-space/demoapp/app/browse/webapp/i18n/i18n.properties create mode 100644 app/single-tenant/personal-space/demoapp/app/browse/webapp/i18n/i18n_de.properties create mode 100644 app/single-tenant/personal-space/demoapp/app/browse/webapp/manifest.json create mode 100644 app/single-tenant/personal-space/demoapp/app/common.cds create mode 100644 app/single-tenant/personal-space/demoapp/app/index.html create mode 100644 app/single-tenant/personal-space/demoapp/app/package.json create mode 100644 app/single-tenant/personal-space/demoapp/app/services.cds create mode 100644 app/single-tenant/personal-space/demoapp/app/xs-app.json create mode 100644 app/single-tenant/personal-space/demoapp/db/data/WDIRSCodeList.csv create mode 100644 app/single-tenant/personal-space/demoapp/db/data/sap.attachments-UploadScanStates.csv create mode 100644 app/single-tenant/personal-space/demoapp/db/data/sap.capire.bookshop-Authors.csv create mode 100644 app/single-tenant/personal-space/demoapp/db/data/sap.capire.bookshop-Books.csv create mode 100644 app/single-tenant/personal-space/demoapp/db/data/sap.capire.bookshop-Books_texts.csv create mode 100644 app/single-tenant/personal-space/demoapp/db/data/sap.capire.bookshop-Genres.csv create mode 100644 app/single-tenant/personal-space/demoapp/db/package-lock.json create mode 100644 app/single-tenant/personal-space/demoapp/db/package.json create mode 100644 app/single-tenant/personal-space/demoapp/db/pom.xml create mode 100644 app/single-tenant/personal-space/demoapp/db/schema.cds create mode 100644 app/single-tenant/personal-space/demoapp/mta.yaml create mode 100644 app/single-tenant/personal-space/demoapp/package-lock.json create mode 100644 app/single-tenant/personal-space/demoapp/package.json create mode 100644 app/single-tenant/personal-space/demoapp/pom.xml create mode 100644 app/single-tenant/personal-space/demoapp/srv/admin-service.cds create mode 100644 app/single-tenant/personal-space/demoapp/srv/attachment-extension.cds create mode 100644 app/single-tenant/personal-space/demoapp/srv/cat-service.cds create mode 100644 app/single-tenant/personal-space/demoapp/srv/pom.xml create mode 100644 app/single-tenant/personal-space/demoapp/srv/src/main/java/customer/demoapp/Application.java create mode 100644 app/single-tenant/personal-space/demoapp/srv/src/main/java/customer/demoapp/handlers/AdminServiceHandler.java create mode 100644 app/single-tenant/personal-space/demoapp/srv/src/main/java/customer/demoapp/handlers/CatalogServiceHandler.java create mode 100644 app/single-tenant/personal-space/demoapp/srv/src/main/resources/application.yaml create mode 100644 app/single-tenant/personal-space/demoapp/srv/src/main/resources/messages.properties create mode 100644 app/single-tenant/personal-space/demoapp/srv/src/test/java/customer/demoapp/handlers/CatalogServiceHandlerTest.java create mode 100644 app/single-tenant/personal-space/demoapp/srv/user-service.cds create mode 100644 app/single-tenant/personal-space/demoapp/xs-security.json diff --git a/.github/workflows/SAPUI5_Version_Monitoring.yml b/.github/workflows/SAPUI5_Version_Monitoring.yml index 10b48de55..c0a688d63 100644 --- a/.github/workflows/SAPUI5_Version_Monitoring.yml +++ b/.github/workflows/SAPUI5_Version_Monitoring.yml @@ -14,10 +14,10 @@ jobs: pull-requests: write steps: - - name: Checkout the develop_deploy branch + - name: Checkout the develop branch uses: actions/checkout@v6 with: - ref: develop_deploy + ref: develop - name: Install dependencies run: | @@ -26,9 +26,9 @@ jobs: id: run_script run: | #!/bin/bash - + # Define the target file - FILE_PATH="cap-notebook/demoapp/app/index.html" + FILE_PATH="app/single-tenant/central-space/demoapp/app/index.html" # Function to get the latest version and its corresponding latest patch version fetch_versions() { @@ -107,5 +107,5 @@ jobs: Current Version: ${{ steps.run_script.outputs.current_version }} Latest patch version: ${{ steps.run_script.outputs.latest_version }} branch: 'update-sapui5-version' - base: develop_deploy + base: develop assignees: yashmeet29 diff --git a/.github/workflows/cfdeploy.yml b/.github/workflows/cfdeploy.yml index 16d0f5bfa..b8751d4ff 100644 --- a/.github/workflows/cfdeploy.yml +++ b/.github/workflows/cfdeploy.yml @@ -53,18 +53,6 @@ jobs: mvn clean install -P unit-tests -DskipIntegrationTests echo "✅ Build and packaging completed successfully!" - - name: Verify and Checkout Deploy Branch 🔄 - run: | - git fetch origin - echo "📂 Verifying 'local_deploy' branch..." - if git rev-parse --verify origin/local_deploy; then - git checkout local_deploy - echo "✅ Branch checked out successfully!" - else - echo "❌ Branch 'local_deploy' not found. Please verify the branch name." - exit 1 - fi - - name: Set REPOSITORY_ID 🔍 id: set_repository_id run: | @@ -88,7 +76,7 @@ jobs: echo "Current Branch: 📂" git branch pwd - cd /home/runner/work/sdm/sdm/cap-notebook/demoapp/app + cd /home/runner/work/sdm/sdm/app/single-tenant/personal-space/demoapp/app echo "Changed to app directory 📂" pwd @@ -143,25 +131,13 @@ jobs: java-version: 21 distribution: 'temurin' - - name: Verify and Checkout Deploy Branch 🔄 - run: | - git fetch origin - echo "📂 Verifying 'develop_deploy' branch..." - if git rev-parse --verify origin/develop_deploy; then - git checkout develop_deploy - echo "✅ Branch checked out successfully!" - else - echo "❌ Branch 'develop_deploy' not found. Please verify the branch name." - exit 1 - fi - - name: Override cds.services.version (runtime only) if: ${{ github.event.inputs.cds_services_version != '' }} env: TARGET_CDS_SERVICES_VERSION: ${{ github.event.inputs.cds_services_version }} run: | echo "Override requested: cds.services.version -> ${TARGET_CDS_SERVICES_VERSION}" - FILES=$(grep -Rl "" . | grep pom.xml || true) + FILES=$(grep -Rl "" app/single-tenant/central-space/demoapp | grep pom.xml || true) if [ -z "$FILES" ]; then echo "No pom.xml files with found" >&2; exit 1; fi @@ -223,7 +199,7 @@ jobs: echo "Current Branch: 📂" git branch pwd - cd /home/runner/work/sdm/sdm/cap-notebook/demoapp + cd /home/runner/work/sdm/sdm/app/single-tenant/central-space/demoapp cd app echo "🔄 Removing node_modules for fresh install..." diff --git a/.github/workflows/multiTenancyDeployLocal.yml b/.github/workflows/multiTenancyDeployLocal.yml index 30d936c54..79c60c1f8 100644 --- a/.github/workflows/multiTenancyDeployLocal.yml +++ b/.github/workflows/multiTenancyDeployLocal.yml @@ -57,19 +57,13 @@ jobs: npm install -g mbt echo "✅ MBT installation complete!" - - name: Clone the cloud-cap-samples-java repo 🌐 - run: | - echo "🔄 Cloning repository..." - git clone --depth 1 --branch local_mtTests https://github.com/vibhutikumar07/cloud-cap-samples-java.git - echo "✅ Repository cloned!" - - name: Override cds.services.version (runtime only) if: ${{ github.event.inputs.cds_services_version != '' }} env: TARGET_CDS_SERVICES_VERSION: ${{ github.event.inputs.cds_services_version }} run: | echo "Override requested: cds.services.version -> ${TARGET_CDS_SERVICES_VERSION}" - FILES=$(grep -Rl "" . | grep pom.xml || true) + FILES=$(grep -Rl "" app/multi-tenant/personal-space/cloud-cap-samples-java | grep pom.xml || true) if [ -z "$FILES" ]; then echo "No pom.xml files with found" >&2; exit 1; fi @@ -82,22 +76,28 @@ jobs: shell: bash - name: Change directory to cloud-cap-samples-java 📂 - working-directory: cloud-cap-samples-java + working-directory: app/multi-tenant/personal-space/cloud-cap-samples-java run: | pwd echo "✔️ Directory changed!" + - name: Set REPOSITORY_ID 🔍 + id: set_repository_id + run: | + echo "repository_id=${{ secrets.REPOSITORY_ID }}" >> $GITHUB_OUTPUT + - name: Run mbt build 🔨 - working-directory: cloud-cap-samples-java + working-directory: app/multi-tenant/personal-space/cloud-cap-samples-java run: | echo "🚀 Running MBT build..." echo "java version:" java --version + sed -i 's|__REPOSITORY_ID__|${{ steps.set_repository_id.outputs.repository_id }}|g' mta.yaml mbt build echo "✅ MBT build completed!" - name: Deploy to Cloud Foundry ☁️ - working-directory: cloud-cap-samples-java + working-directory: app/multi-tenant/personal-space/cloud-cap-samples-java run: | echo "🚀 Deploying to -s ${{ steps.determine_space.outputs.space }}..." echo "🔧 Installing Cloud Foundry CLI and plugins..." diff --git a/.github/workflows/multiTenant_deploy_and_Integration_test.yml b/.github/workflows/multiTenant_deploy_and_Integration_test.yml index 259fc53fc..66bd44aa6 100644 --- a/.github/workflows/multiTenant_deploy_and_Integration_test.yml +++ b/.github/workflows/multiTenant_deploy_and_Integration_test.yml @@ -51,29 +51,29 @@ jobs: npm install -g mbt echo "✅ MBT installation complete!" - - name: Clone the cloud-cap-samples-java repo 🌐 - run: | - echo "🔄 Cloning repository..." - git clone --depth 1 --branch mtTests https://github.com/vibhutikumar07/cloud-cap-samples-java.git - echo "✅ Repository cloned!" - - name: Change directory to cloud-cap-samples-java 📂 - working-directory: cloud-cap-samples-java + working-directory: app/multi-tenant/central-space/cloud-cap-samples-java run: | pwd echo "✔️ Directory changed!" + - name: Set REPOSITORY_ID 🔍 + id: set_repository_id + run: | + echo "repository_id=${{ secrets.REPOSITORY_ID }}" >> $GITHUB_OUTPUT + - name: Run mbt build 🔨 - working-directory: cloud-cap-samples-java + working-directory: app/multi-tenant/central-space/cloud-cap-samples-java run: | echo "🚀 Running MBT build..." echo "java version:" java --version + sed -i 's|__REPOSITORY_ID__|${{ steps.set_repository_id.outputs.repository_id }}|g' mta.yaml mbt build echo "✅ MBT build completed!" - name: Deploy to Cloud Foundry ☁️ - working-directory: cloud-cap-samples-java + working-directory: app/multi-tenant/central-space/cloud-cap-samples-java run: | echo "🚀 Deploying to ${{ secrets.CF_SPACE }}..." echo "🔧 Installing Cloud Foundry CLI and plugins..." diff --git a/.github/workflows/multiTenant_deploy_and_Integration_test_LatestVersion.yml b/.github/workflows/multiTenant_deploy_and_Integration_test_LatestVersion.yml index 16a81e7a9..8681a2fd4 100644 --- a/.github/workflows/multiTenant_deploy_and_Integration_test_LatestVersion.yml +++ b/.github/workflows/multiTenant_deploy_and_Integration_test_LatestVersion.yml @@ -47,12 +47,6 @@ jobs: npm install -g mbt echo "✅ MBT installation complete!" - - name: Clone the cloud-cap-samples-java repo 🌐 - run: | - echo "🔄 Cloning repository..." - git clone --depth 1 --branch mtTests https://github.com/vibhutikumar07/cloud-cap-samples-java.git - echo "✅ Repository cloned!" - - name: Override cds.services.version (runtime only) env: TARGET_CDS_SERVICES_VERSION: 4.3.1 @@ -60,7 +54,7 @@ jobs: set -e echo "=== cds.services.version Override Step ===" echo "Target version to apply: ${TARGET_CDS_SERVICES_VERSION}" - FILES=$(grep -Rl "" . | grep pom.xml || true) + FILES=$(grep -Rl "" app/multi-tenant/central-space/cloud-cap-samples-java | grep pom.xml || true) if [ -z "$FILES" ]; then echo "No pom.xml files with found" >&2; exit 1; fi @@ -76,7 +70,7 @@ jobs: done echo "\nResolving effective value BEFORE override via mvn help:evaluate ..." - RESOLVED_BEFORE=$(mvn -q -DforceStdout help:evaluate -Dexpression=cds.services.version || true) + RESOLVED_BEFORE=$(mvn -q -DforceStdout help:evaluate -f app/multi-tenant/central-space/cloud-cap-samples-java/pom.xml -Dexpression=cds.services.version || true) echo "Effective cds.services.version before override: '${RESOLVED_BEFORE}'" if [ "${RESOLVED_BEFORE}" = "${TARGET_CDS_SERVICES_VERSION}" ]; then echo "NOTE: Effective value already equals target; files will still be normalized to target string." @@ -92,7 +86,7 @@ jobs: grep -R "" $FILES || true echo "\nResolving effective value AFTER override via mvn help:evaluate ..." - RESOLVED_AFTER=$(mvn -q -DforceStdout help:evaluate -Dexpression=cds.services.version || true) + RESOLVED_AFTER=$(mvn -q -DforceStdout help:evaluate -f app/multi-tenant/central-space/cloud-cap-samples-java/pom.xml -Dexpression=cds.services.version || true) echo "Effective cds.services.version after override: '${RESOLVED_AFTER}'" if [ "${RESOLVED_AFTER}" != "${TARGET_CDS_SERVICES_VERSION}" ]; then echo "WARNING: Resolved value does not match target (profiles or parent POM could be overriding it)." >&2 @@ -104,23 +98,29 @@ jobs: - name: Change directory to cloud-cap-samples-java 📂 - working-directory: cloud-cap-samples-java + working-directory: app/multi-tenant/central-space/cloud-cap-samples-java run: | pwd echo "✔️ Directory changed!" + - name: Set REPOSITORY_ID 🔍 + id: set_repository_id + run: | + echo "repository_id=${{ secrets.REPOSITORY_ID }}" >> $GITHUB_OUTPUT + - name: Run mbt build 🔨 - working-directory: cloud-cap-samples-java + working-directory: app/multi-tenant/central-space/cloud-cap-samples-java run: | echo "🚀 Running MBT build..." echo "java version:" java --version + sed -i 's|__REPOSITORY_ID__|${{ steps.set_repository_id.outputs.repository_id }}|g' mta.yaml mbt build echo "✅ MBT build completed!" - name: Deploy to Cloud Foundry ☁️ - working-directory: cloud-cap-samples-java + working-directory: app/multi-tenant/central-space/cloud-cap-samples-java run: | echo "🚀 Deploying to ${{ secrets.CF_SPACE }}..." echo "🔧 Installing Cloud Foundry CLI and plugins..." diff --git a/.github/workflows/singleTenant_deploy_and_Integration_test.yml b/.github/workflows/singleTenant_deploy_and_Integration_test.yml index b4f1d2b44..a7b495160 100644 --- a/.github/workflows/singleTenant_deploy_and_Integration_test.yml +++ b/.github/workflows/singleTenant_deploy_and_Integration_test.yml @@ -33,16 +33,6 @@ jobs: java-version: 21 distribution: 'temurin' - - name: Verify and Checkout Deploy Branch - run: | - git fetch origin - if git rev-parse --verify origin/develop_deploy; then - git checkout develop_deploy - else - echo "Branch 'develop_deploy' not found. Please verify the branch name." - exit 1 - fi - - name: Deleting the sdm directory for fresh build run: | pwd @@ -70,12 +60,17 @@ jobs: # mvn dependency:get -Dartifact=com.sap.cds:sdm-root:LATEST -DrepoUrl=https://maven.pkg.github.com/cap-java/sdm # mvn dependency:get -Dartifact=com.sap.cds:sdm:LATEST -DrepoUrl=https://maven.pkg.github.com/cap-java/sdm + - name: Set REPOSITORY_ID 🔍 + id: set_repository_id + run: | + echo "repository_id=${{ secrets.REPOSITORY_ID }}" >> $GITHUB_OUTPUT + - name: Prepare and Deploy to Cloud Foundry run: | echo "Current Branch......" git branch pwd - cd /home/runner/work/sdm/sdm/cap-notebook/demoapp + cd /home/runner/work/sdm/sdm/app/single-tenant/central-space/demoapp # Removing node_modules & package-lock.json cd app rm -rf node_modules package-lock.json @@ -83,7 +78,7 @@ jobs: npm i cd .. - + # Replace placeholder with actual REPOSITORY_ID value sed -i 's|__REPOSITORY_ID__|'${{ steps.set_repository_id.outputs.repository_id }}'|g' ./mta.yaml diff --git a/.github/workflows/singleTenant_deploy_and_Integration_test_LatestVersion.yml b/.github/workflows/singleTenant_deploy_and_Integration_test_LatestVersion.yml index c2e110285..50bae680d 100644 --- a/.github/workflows/singleTenant_deploy_and_Integration_test_LatestVersion.yml +++ b/.github/workflows/singleTenant_deploy_and_Integration_test_LatestVersion.yml @@ -33,16 +33,6 @@ jobs: java-version: 21 distribution: 'temurin' - - name: Verify and Checkout Deploy Branch - run: | - git fetch origin - if git rev-parse --verify origin/develop_deploy; then - git checkout develop_deploy - else - echo "Branch 'develop_deploy' not found. Please verify the branch name." - exit 1 - fi - - name: Override cds.services.version (runtime only) env: TARGET_CDS_SERVICES_VERSION: 4.3.1 @@ -50,7 +40,7 @@ jobs: set -e echo "=== cds.services.version Override Step ===" echo "Target version to apply: ${TARGET_CDS_SERVICES_VERSION}" - FILES=$(grep -Rl "" . | grep pom.xml || true) + FILES=$(grep -Rl "" app/single-tenant/central-space/demoapp | grep pom.xml || true) if [ -z "$FILES" ]; then echo "No pom.xml files with found" >&2; exit 1; fi @@ -66,7 +56,7 @@ jobs: done echo "\nResolving effective value BEFORE override via mvn help:evaluate ..." - RESOLVED_BEFORE=$(mvn -q -DforceStdout help:evaluate -Dexpression=cds.services.version || true) + RESOLVED_BEFORE=$(mvn -q -DforceStdout help:evaluate -f app/single-tenant/central-space/demoapp/pom.xml -Dexpression=cds.services.version || true) echo "Effective cds.services.version before override: '${RESOLVED_BEFORE}'" if [ "${RESOLVED_BEFORE}" = "${TARGET_CDS_SERVICES_VERSION}" ]; then echo "NOTE: Effective value already equals target; files will still be normalized to target string." @@ -82,7 +72,7 @@ jobs: grep -R "" $FILES || true echo "\nResolving effective value AFTER override via mvn help:evaluate ..." - RESOLVED_AFTER=$(mvn -q -DforceStdout help:evaluate -Dexpression=cds.services.version || true) + RESOLVED_AFTER=$(mvn -q -DforceStdout help:evaluate -f app/single-tenant/central-space/demoapp/pom.xml -Dexpression=cds.services.version || true) echo "Effective cds.services.version after override: '${RESOLVED_AFTER}'" if [ "${RESOLVED_AFTER}" != "${TARGET_CDS_SERVICES_VERSION}" ]; then echo "WARNING: Resolved value does not match target (profiles or parent POM could be overriding it)." >&2 @@ -121,12 +111,17 @@ jobs: # mvn dependency:get -Dartifact=com.sap.cds:sdm-root:LATEST -DrepoUrl=https://maven.pkg.github.com/cap-java/sdm # mvn dependency:get -Dartifact=com.sap.cds:sdm:LATEST -DrepoUrl=https://maven.pkg.github.com/cap-java/sdm + - name: Set REPOSITORY_ID 🔍 + id: set_repository_id + run: | + echo "repository_id=${{ secrets.REPOSITORY_ID }}" >> $GITHUB_OUTPUT + - name: Prepare and Deploy to Cloud Foundry run: | echo "Current Branch......" git branch pwd - cd /home/runner/work/sdm/sdm/cap-notebook/demoapp + cd /home/runner/work/sdm/sdm/app/single-tenant/central-space/demoapp # Removing node_modules & package-lock.json cd app rm -rf node_modules package-lock.json @@ -134,7 +129,7 @@ jobs: npm i cd .. - + # Replace placeholder with actual REPOSITORY_ID value sed -i 's|__REPOSITORY_ID__|'${{ steps.set_repository_id.outputs.repository_id }}'|g' ./mta.yaml diff --git a/.github/workflows/sonarqube.yml b/.github/workflows/sonarqube.yml index 8260b7608..fb67c7044 100644 --- a/.github/workflows/sonarqube.yml +++ b/.github/workflows/sonarqube.yml @@ -55,7 +55,7 @@ jobs: -Dsonar.junit.reportPaths=sdm/target/surefire-reports \ -Dsonar.coverage.jacoco.xmlReportPaths=sdm/target/site/jacoco/jacoco.xml \ -Dsonar.inclusions=**/*.java \ - -Dsonar.exclusions=**/target/**,**/node_modules/**,sdm/src/main/test/**,cap-notebook/*.capnb,sdm/src/main/java/com/sap/cds/sdm/model/**,sdm/src/main/java/com/sap/cds/sdm/caching/CacheKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/RepoKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/TokenCacheKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/SecondaryTypesKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/SecondaryPropertiesKey.java \ + -Dsonar.exclusions=**/target/**,**/node_modules/**,sdm/src/main/test/**,app/**/*.capnb,sdm/src/main/java/com/sap/cds/sdm/model/**,sdm/src/main/java/com/sap/cds/sdm/caching/CacheKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/RepoKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/TokenCacheKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/SecondaryTypesKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/SecondaryPropertiesKey.java \ -Dsonar.java.file.suffixes=.java \ -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \ -Dsonar.login=${{ secrets.SONAR_TOKEN }} \ @@ -71,7 +71,7 @@ jobs: -Dsonar.junit.reportPaths=sdm/target/surefire-reports \ -Dsonar.coverage.jacoco.xmlReportPaths=sdm/target/site/jacoco/jacoco.xml \ -Dsonar.inclusions=**/*.java \ - -Dsonar.exclusions=**/target/**,**/node_modules/**,sdm/src/main/test/**,cap-notebook/*.capnb,sdm/src/main/java/com/sap/cds/sdm/model/**,sdm/src/main/java/com/sap/cds/sdm/caching/CacheKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/RepoKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/TokenCacheKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/SecondaryTypesKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/SecondaryPropertiesKey.java \ + -Dsonar.exclusions=**/target/**,**/node_modules/**,sdm/src/main/test/**,app/**/*.capnb,sdm/src/main/java/com/sap/cds/sdm/model/**,sdm/src/main/java/com/sap/cds/sdm/caching/CacheKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/RepoKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/TokenCacheKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/SecondaryTypesKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/SecondaryPropertiesKey.java \ -Dsonar.java.file.suffixes=.java \ -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \ -Dsonar.login=${{ secrets.SONAR_TOKEN }} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/.cdsprettier.json b/app/multi-tenant/central-space/cloud-cap-samples-java/.cdsprettier.json new file mode 100644 index 000000000..f3d9ca868 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/.cdsprettier.json @@ -0,0 +1,12 @@ +{ + "alignExpressionsAndConditions": true, + "alignExprAndCondWithinBlock": true, + "alignCompositionStructToRight": true, + "keepOriginalEmptyLines": false, + "openingBraceInNewLine": false, + "alignValuesInAnnotations": true, + "alignColonsInAnnotations": true, + "alignPostAnnotations": true, + "alignPreAnnotations": true, + "alignTypes": true +} \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/.cdsrc.json b/app/multi-tenant/central-space/cloud-cap-samples-java/.cdsrc.json new file mode 100644 index 000000000..0adb9aa2a --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/.cdsrc.json @@ -0,0 +1,20 @@ +{ + "requires": { + "multitenancy": true, + "extensibility": true, + "toggles": true + }, + "odata": { + "version": "v4" + }, + "fiori": { + "draft_messages": false + }, + "profile": "with-mtx-sidecar", + "cdsc": { + "newParser": true + }, + "sql": { + "native_hana_associations": false + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/.github/workflows/maven.yml b/app/multi-tenant/central-space/cloud-cap-samples-java/.github/workflows/maven.yml new file mode 100644 index 000000000..f083578d7 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/.github/workflows/maven.yml @@ -0,0 +1,30 @@ +# This workflow will build a Java project with Maven +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: Java CI with Maven + +on: + push: + branches: + - main + - postgres + pull_request: + branches: + - main + - postgres + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up JDK + uses: actions/setup-java@v4 + with: + java-version: 21 + distribution: 'sapmachine' + - name: Build with Maven + run: mvn -ntp -B clean install diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/.gitignore b/app/multi-tenant/central-space/cloud-cap-samples-java/.gitignore new file mode 100644 index 000000000..f9986b41c --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/.gitignore @@ -0,0 +1,38 @@ +gen/ +edmx/ +schema-h2.sql +default-env.json +openapi.json +.env +.values.yaml + +bin/ +target/ +.java-version +.flattened-pom.xml +.classpath +.project +.settings +.vscode +.idea +*.iml + +node/ +node_modules/ + +.mta/ +*.mtar +mta.yaml + +*.log* +gc_history* +hs_err* +.DS_Store + +*.db +*.sqlite* + +.cdsrc-private.json + +/chart/ +.reloadtrigger diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/.reuse/dep5 b/app/multi-tenant/central-space/cloud-cap-samples-java/.reuse/dep5 new file mode 100644 index 000000000..57d1ebed0 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/.reuse/dep5 @@ -0,0 +1,29 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: cloud-cap-samples-java +Upstream-Contact: +Source: https://github.com/SAP-samples/cloud-cap-samples-java +Disclaimer: The code in this project may include calls to APIs (“API Calls”) of + SAP or third-party products or services developed outside of this project + (“External Products”). + “APIs” means application programming interfaces, as well as their respective + specifications and implementing code that allows software to communicate with + other software. + API Calls to External Products are not licensed under the open source license + that governs this project. The use of such API Calls and related External + Products are subject to applicable additional agreements with the relevant + provider of the External Products. In no event shall the open source license + that governs this project grant any rights in or to any External Products,or + alter, expand or supersede any terms of the applicable additional agreements. + If you have a valid license agreement with SAP for the use of a particular SAP + External Product, then you may make use of any API Calls included in this + project’s code for that SAP External Product, subject to the terms of such + license agreement. If you do not have a valid license agreement for the use of + a particular SAP External Product, then you may only make use of any API Calls + in this project for that SAP External Product for your internal, non-productive + and non-commercial test and evaluation of such API Calls. Nothing herein grants + you any rights to use or access any SAP External Product, or provide any third + parties the right to use of access any SAP External Product, through API Calls. + +Files: * +Copyright: 2019-2020 SAP SE or an SAP affiliate company and cap-cloud-samples-java +License: Apache-2.0 diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/.tours/sample-tour.tour b/app/multi-tenant/central-space/cloud-cap-samples-java/.tours/sample-tour.tour new file mode 100644 index 000000000..1847fb477 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/.tours/sample-tour.tour @@ -0,0 +1,201 @@ +{ + "$schema": "https://aka.ms/codetour-schema", + "title": "CAP Bookshop Sample", + "steps": [ + { + "file": "README.md", + "description": "### Welcome to CAP Samples for Java!\n\nThis tour leads you through a sample project for the [SAP Cloud Application Programming Model (CAP)](https://cap.cloud.sap), explaining some important concepts.\n\nLet's get started!", + "line": 2, + "title": "Welcome" + }, + { + "file": "README.md", + "description": "### Bookshop Sample\n\nThe sample implements a simple bookshop demonstrating selected features of CAP and introduces some essential concepts of CAP for Java:\n\n- [Project Setup](https://cap.cloud.sap/docs/java/getting-started) and [Layouts](https://cap.cloud.sap/docs/java/getting-started#project-layout)\n- [Domain Modeling](https://cap.cloud.sap/docs/guides/domain-models)\n- [Defining Services](https://cap.cloud.sap/docs/guides/services#defining-services)\n- [Generic Providers](https://cap.cloud.sap/docs/guides/generic)\n- [Adding Custom Logic](https://cap.cloud.sap/docs/java/provisioning-api)\n- [Using Databases](https://cap.cloud.sap/docs/guides/databases)", + "line": 33 + }, + { + "file": "db/books.cds", + "description": "### Entity and Type Definitions\n\nEvery CAP project usually starts with the [domain model](https://cap.cloud.sap/docs/guides/domain-models). It defines the entities and types you can use in the services your application wants to offer. Showcased here are some entity definitions which are used by the bookshop application, using [CDL](https://cap.cloud.sap/docs/cds/cdl).\n\nConcepts used:\n\n- [Entity and Type Definitions](https://cap.cloud.sap/docs/cds/cdl#entity-and-type-definitions)\n- [Associations & Compositions](https://cap.cloud.sap/docs/cds/cdl#associations)\n- [Input Validation](https://cap.cloud.sap/docs/cds/annotations#input-validation)\n- [Declaring Localized Data](https://cap.cloud.sap/docs/guides/localized-data#declaring-localized-data)", + "line": 55, + "selection": { + "start": { + "line": 1, + "character": 1 + }, + "end": { + "line": 55, + "character": 1 + } + } + }, + { + "file": "srv/cat-service.cds", + "description": "### Service Definitions\n\nA [service](https://cap.cloud.sap/docs/cds/cdl#service-definitions) interface exposes chosen entities of your domain model for consumption. The endpoint of the exposed service is usually constructed by its name following specific conventions. Here, however the endpoint path to the `CatalogService` is overwritten by the `@path : 'browse'` annotation.\n\nThis `CatalogService` showcases the API for browsing books and adding reviews and demonstrates:\n\n- [Services](https://cap.cloud.sap/docs/java/consumption-api)\n- [Import Directives](https://cap.cloud.sap/docs/cds/cdl#imports)\n- [Namespaces](https://cap.cloud.sap/docs/cds/cdl#namespaces)\n- [Views and Projections](https://cap.cloud.sap/docs/cds/cdl#views)\n- [Annotations](https://cap.cloud.sap/docs/cds/cdl#annotations)\n- [Bound and Unbound Actions](https://cap.cloud.sap/docs/cds/cdl#actions)\n- [Restrictions](https://cap.cloud.sap/docs/guides/authorization#restrictions)", + "line": 35, + "selection": { + "start": { + "line": 1, + "character": 1 + }, + "end": { + "line": 35, + "character": 2 + } + } + }, + { + "file": "srv/admin-service.cds", + "description": "### Service Definitions\n\nHere is another example of a service interface, demonstrating:\n\n- [Restriction using `@requires`](https://cap.cloud.sap/docs/guides/authorization#requires)\n- [Search Capabilities](https://cap.cloud.sap/docs/guides/generic#search-capabilities)\n- Enablement of [Draft-Based Editing](https://cap.cloud.sap/docs/advanced/fiori#fiori-draft-support) for exposed entities", + "line": 46, + "selection": { + "start": { + "line": 1, + "character": 1 + }, + "end": { + "line": 46, + "character": 1 + } + } + }, + { + "file": "srv/src/main/java/my/bookshop/handlers/CatalogServiceHandler.java", + "description": "### Event Handler\n\nAfter defining your domain model and services you can [implement event handlers](https://cap.cloud.sap/docs/java/application-services) reacting to events triggered by these services. This file, for example, showcases an [event handler](https://cap.cloud.sap/docs/java/provisioning-api) for the `CatalogService`. There are various handler implementations reacting to specific [event phases](https://cap.cloud.sap/docs/java/provisioning-api#phases), as showcased in the next steps of this tour.", + "selection": { + "start": { + "line": 77, + "character": 2 + }, + "end": { + "line": 180, + "character": 3 + } + } + }, + { + "file": "srv/src/main/java/my/bookshop/handlers/CatalogServiceHandler.java", + "description": "### Event Handler\n\nThe method `beforeAddReview` demonstrated here is used to validate reviews that are about to be persisted, checking whether the author of the review already created one for the given book. The `ServiceException` thrown in such a case aborts further processing of the current event (of adding a review). The method is bound to the `Before` [event phase](https://cap.cloud.sap/docs/java/provisioning-api#phases), meaning it will be triggerd before the core processing of the event. In the next steps you will see some other event phase handling examples.\n\nThe query run against the database for the check is constructed via the [Query Builder Java API](https://cap.cloud.sap/docs/java/query-api#the-query-builders-java-api).\n\nConcepts used:\n\n- [Event Phase: `Before`](https://cap.cloud.sap/docs/java/provisioning-api#before)\n- [Building CQN Queries](https://cap.cloud.sap/docs/java/query-api)\n- [Indicating Errors](https://cap.cloud.sap/docs/java/indicating-errors)\n- [Static CDS Model](https://cap.cloud.sap/docs/java/advanced#staticmodel)", + "line": 94, + "selection": { + "start": { + "line": 77, + "character": 2 + }, + "end": { + "line": 94, + "character": 3 + } + } + }, + { + "file": "srv/src/main/java/my/bookshop/handlers/CatalogServiceHandler.java", + "description": "### Event Handler\n\nThe `onAddReview` method is bound to the `On` phase of the `AddReview` event, as defined by the bound action in the [`CatalogService`](srv/cat-service.cds). Aside from the `Insert` [query execution](https://cap.cloud.sap/docs/java/query-execution#queries) demonstrated here, you can also see how to [complete the event processing](https://cap.cloud.sap/docs/java/provisioning-api#eventcompletion) necessary in the `On` phase. In this example we are setting the `Reviews` object from the query result in the event context.\n\nConcepts used:\n\n- [Event Phase: `On`](https://cap.cloud.sap/docs/java/provisioning-api#on)\n- [Event Contexts](https://cap.cloud.sap/docs/java/provisioning-api#eventcontext)\n- [Building CQN Queries](https://cap.cloud.sap/docs/java/query-api)\n- [Static CDS Model](https://cap.cloud.sap/docs/java/advanced#staticmodel)", + "line": 115, + "selection": { + "start": { + "line": 96, + "character": 2 + }, + "end": { + "line": 115, + "character": 3 + } + } + }, + { + "file": "srv/cat-service.cds", + "description": "### Bound Action\n\nThe [bound action](https://cap.cloud.sap/docs/cds/cdl#actions) `addReview` here is bound to the `Books` entity within the [`CatalogService`](srv/cat-service.cds). Modeling an action provides you with a more specific [event context](https://cap.cloud.sap/docs/java/provisioning-api#eventcontext) object, such as the `AddReviewContext`, which is used, as shown in the previous step, to implement the `AddReview` event processing.", + "line": 10, + "selection": { + "start": { + "line": 10, + "character": 9 + }, + "end": { + "line": 10, + "character": 91 + } + } + }, + { + "file": "srv/cat-service.cds", + "description": "### Unbound Action\n\nIn contrast, `submitOrder` is modeled as an [unbound action](https://cap.cloud.sap/docs/cds/cdl#actions), meaning it is not bound to an individual entity as `addReview` is bound to `Books`.\n\n[Actions and Functions](https://cap.cloud.sap/docs/java/application-services#actions) as the examples shown here and in the previous step, are generally used to enhance your application service with custom operations.", + "line": 21, + "selection": { + "start": { + "line": 19, + "character": 5 + }, + "end": { + "line": 21, + "character": 7 + } + } + }, + { + "file": "srv/src/main/java/my/bookshop/handlers/BookRatingInitialization.java", + "description": "### Application Start-Up\n\nYou can not only register event handlers for your services, but also handlers that are executed during application start-up. As demonstrated here, for example, we initialize the average rating for all books in the bookshop based on their review ratings, using the [`After`](https://cap.cloud.sap/docs/java/provisioning-api#after) phase of the [`ApplicationLifecycleService.EVENT_APPLICATION_PREPARED`](https://www.javadoc.io/doc/com.sap.cds/cds-services-api/latest/com/sap/cds/services/application/ApplicationPreparedEventContext.html) event.", + "line": 30, + "selection": { + "start": { + "line": 27, + "character": 2 + }, + "end": { + "line": 30, + "character": 3 + } + } + }, + { + "file": "srv/src/main/java/my/bookshop/config/DestinationConfiguration.java", + "description": "### Application Start-Up\n\nAnother example of this you can find here in the `DestinationConfiguration` handler.", + "line": 35, + "selection": { + "start": { + "line": 22, + "character": 2 + }, + "end": { + "line": 35, + "character": 3 + } + } + }, + { + "file": "srv/src/main/java/my/bookshop/handlers/AdminServiceHandler.java", + "description": "### SAP Fiori Drafts Support\n\nHere, you can see a handler bound to events of the [SAP Fiori Draft](https://cap.cloud.sap/docs/java/fiori-drafts) flow. Draft-specific events are enabled by annotating entities with `@odata.draft.enabled` as in the [`AdminService`](srv/admin-service.cds).\n\nConcepts used:\n\n- [Draft-based Editing](https://cap.cloud.sap/docs/advanced/fiori#fiori-draft-support)", + "line": 158, + "selection": { + "start": { + "line": 142, + "character": 2 + }, + "end": { + "line": 158, + "character": 3 + } + } + }, + { + "file": "app/browse/fiori-service.cds", + "description": "### SAP Fiori Elements Support\n\nCAP for Java supports SAP Fiori Elements annotations out-of-the-box. The `fiori-service.cds` files in the [app](app) folder altogether add a [SAP Fiori elements application](https://cap.cloud.sap/docs/advanced/fiori) to bookshop, thereby introducing to:\n - [OData Annotations](https://cap.cloud.sap/docs/advanced/odata) in `.cds` files\n - Support for [SAP Fiori Draft](https://cap.cloud.sap/docs/advanced/fiori#fiori-draft-support)\n - Support for [Value Helps](https://cap.cloud.sap/docs/advanced/fiori#value-help-support)\n - Serving SAP Fiori apps locally\n\n[A Vue.js app](app/vue/index.html) is served as well.\n", + "line": 177, + "selection": { + "start": { + "line": 1, + "character": 1 + }, + "end": { + "line": 201, + "character": 1 + } + } + }, + { + "title": "Summary", + "description": "### Summary\n\nThat's it! You have seen:\n\n- Entity and Type Definitions\n- Service Definitions\n- Event Handler\n- Bound and Unbound Actions\n- Fiori Draft Support\n- SAP Fiori Elements Support\n\nFor more information and details, check our [CAP](https://cap.cloud.sap/docs/) documentation." + } + ], + "description": "Demonstrating CAP for Java" +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/LICENSE b/app/multi-tenant/central-space/cloud-cap-samples-java/LICENSE new file mode 100644 index 000000000..67db85882 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/LICENSE @@ -0,0 +1,175 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + 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 + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + 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 + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + 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. diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/LICENSES/Apache-2.0.txt b/app/multi-tenant/central-space/cloud-cap-samples-java/LICENSES/Apache-2.0.txt new file mode 100644 index 000000000..4ed90b952 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/LICENSES/Apache-2.0.txt @@ -0,0 +1,208 @@ +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, +AND DISTRIBUTION + + 1. Definitions. + + + +"License" shall mean the terms and conditions for use, reproduction, and distribution +as defined by Sections 1 through 9 of this document. + + + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + + + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct +or indirect, to cause the direction or management of such entity, whether +by contract or otherwise, or (ii) ownership of fifty percent (50%) or more +of the outstanding shares, or (iii) beneficial ownership of such entity. + + + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions +granted by this License. + + + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + + + +"Object" form shall mean any form resulting from mechanical transformation +or translation of a Source form, including but not limited to compiled object +code, generated documentation, and conversions to other media types. + + + +"Work" shall mean the work of authorship, whether in Source or Object form, +made available under the License, as indicated by a copyright notice that +is included in or attached to the work (an example is provided in the Appendix +below). + + + +"Derivative Works" shall mean any work, whether in Source or Object 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 the original version +of the Work and any modifications or additions to that Work or Derivative +Works thereof, that is intentionally submitted to Licensor for inclusion in +the Work by the copyright owner or by an individual or Legal Entity authorized +to submit on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication +sent to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor +for the purpose of discussing and improving the Work, but 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 on behalf +of whom a Contribution has been received by Licensor and subsequently incorporated +within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this +License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable copyright license to reproduce, prepare +Derivative Works of, publicly display, publicly perform, sublicense, and distribute +the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of 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. diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/README.md b/app/multi-tenant/central-space/cloud-cap-samples-java/README.md new file mode 100644 index 000000000..685fb0d96 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/README.md @@ -0,0 +1,591 @@ + +# Welcome to CAP Samples for Java + +![CI status](https://github.com/SAP-samples/cloud-cap-samples-java/workflows/Java%20CI%20with%20Maven/badge.svg) +[![REUSE status](https://api.reuse.software/badge/github.com/SAP-samples/cloud-cap-samples-java)](https://api.reuse.software/info/github.com/SAP-samples/cloud-cap-samples-java) + +Welcome to the bookshop-java project. It demonstrates how to build business applications using the [CAP Java SDK](https://cap.cloud.sap) providing a book shop web application as an example. The application in this project enables browsing books, managing books, and managing orders. + +![Book Object Page](assets/readmeImages/BookPage.png) + + +## Outline + +- [Overview](#overview) + - [Demonstrated Features](#demonstrated-features) +- [Getting Started](#getting-started) + - [Prerequisites](#prerequisites) + - [Clone Build & Run](#clone-build--run) + - [Using VS Code](#using-vs-code) + - [Using Eclipse](#using-eclipse) + - [Building and Running](#building-and-running) + - [Using IntelliJ Idea (Community and Ultimate)](#using-intellij-idea-community-and-ultimate) + - [Database Setup and Spring Profiles](#database-setup-and-spring-profiles) + - [API_BUSINESS_PARTNER Remote Service and Spring Profiles](#api_business_partner-remote-service-and-spring-profiles) + - [Deploy to SAP Business Technology Platform, Cloud Foundry](#deploy-to-sap-business-technology-platform-cloud-foundry) + - [Deploy to SAP Business Technology Platform, Kyma Runtime](#deploy-to-sap-business-technology-platform-kyma-runtime) + - [Setup Authorizations in SAP Business Technology Platform](#setup-authorizations-in-sap-business-technology-platform) +- [Code Tour](#code-tour) +- [Get Support](#get-support) +- [License](#license) + + +# Overview + +This sample application shows how to conveniently create business applications based on **CDS domain models**, persisting data with **H2**, or **SAP HANA**, and exposing an **OData V4** frontend with an **SAP Fiori** frontend on top. + +This sample uses Spring Boot as an **application framework**. Although a CAP Java application isn’t required to build on Spring Boot, it’s the first choice of framework, as it’s seamlessly integrated. + +The **domain models** are defined using [CDS entity definitions](https://cap.cloud.sap/docs/cds/cdl#entity-and-type-definitions). + +By default, an in-memory H2 database is used for **data persistency**. Once productively deployed to SAP Business Technology Platform, SAP HANA can be used. + +**Services** are defined using [CDS Service Models](https://cap.cloud.sap/docs/cds/cdl#services). The **OData V4 Protocol Adapter** translates the CDS service models into corresponding OData schemas and maps the incoming OData requests to the corresponding CDS services. + +Although CAP provides generic **event handlers** to serve most CRUD requests out-of-the-box, it’s possible to add business logic through [Custom Event Handlers](https://cap.cloud.sap/docs/get-started/in-a-nutshell#adding-custom-logic). + +A SAP Fiori UI is added using predefined SAP Fiori elements templates. **[SAP Fiori annotations](https://cap.cloud.sap/docs/advanced/fiori#fiori-annotations)** add information to the service definitions, on how to render the data. + +CAP provides built-in multitenancy support with out-of-the box tenant isolation. The sample application demonstrates usage of MTX sidecar based on [streamlined MTX](https://cap.cloud.sap/docs/guides/deployment/as-saas?impl-variant=java) and can be deployed as multitenant application. The [deprecated classic MTX](https://cap.cloud.sap/docs/java/multitenancy) setup is shown in the [mtx-classic branch](https://github.com/SAP-samples/cloud-cap-samples-java/tree/mtx-classic) for reference. + +## Demonstrated Features + +Framework and Infrastructure related Features: + +- [Application configuration](https://cap.cloud.sap/docs/java/development#application-configuration) for Spring and CDS using [application.yaml](srv/src/main/resources/application.yaml) +- [Mocking users](/srv/src/main/resources/application.yaml) for local development +- [Authentication & Authorization](https://cap.cloud.sap/docs/java/security) (including user-specific restrictions with `@restrict` in the [Admin Service](/srv/admin-service.cds)) +- [Cloud Foundry Deployment using MTA](https://cap.cloud.sap/docs/advanced/deploy-to-cloud#deploy-using-mta) with XSUAA [Service Bindings](mta-single-tenant.yaml) +- Application Router configuration including authentication via the XSUAA Service. See [package.json](app/package.json), [xs-app.json](app/xs-app.json) and [xs-security.json](xs-security.json) +- [Multitenancy configuration](https://cap.cloud.sap/docs/java/multitenancy) via [mta-multi-tenant.yaml](mta-multi-tenant.yaml), [.cdsrc.json](.cdsrc.json), [sidecar module](mtx-sidecar) +- [Feature toggles](https://cap.cloud.sap/docs/guides/extensibility/feature-toggles?impl-variant=java#limitations). In CF, features can be toggled by assigning the roles `expert` or `premium-customer` to the user. +- [Messaging configuration and handlers](https://cap.cloud.sap/docs/java/messaging-foundation) with local messaging and message brokers. +- Consumption of [Remote services](https://cap.cloud.sap/docs/java/remote-services) in [srv/external.cds] and [srv/notes-mashup.cds] + +Domain Model related Features: + +- [CDS Query Language with a Static CDS Model](https://cap.cloud.sap/docs/java/advanced#staticmodel) in the [Admin Service](srv/src/main/java/my/bookshop/handlers/AdminServiceHandler.java) +- Use of [Aspects](https://cap.cloud.sap/docs/cds/cdl#aspects) in the Model Definition such as the [`managed` or `cuid` Aspect](https://cap.cloud.sap/docs/cds/common#common-reuse-aspects) in [Books](db/books.cds) +- [Input validation](https://cap.cloud.sap/docs/cds/annotations#input-validation) using model annotation `@assert.format` +- [Data Localization](https://cap.cloud.sap/docs/guides/localized-data) for [Books](db/books.cds) +- Use of [Media Data](https://cap.cloud.sap/docs/guides/providing-services#media-data) in [Books](db/books.cds) and [AdminService](srv/admin-service.cds) + +Service Model related Features: + +- [Custom event handlers](https://cap.cloud.sap/docs/java/provisioning-api) such as the [Custom business logic for the Admin Service](srv/src/main/java/my/bookshop/handlers/AdminServiceHandler.java) +- [Custom actions](https://cap.cloud.sap/docs/cds/cdl#actions) such as `addToOrder` in the [Admin Service](srv/admin-service.cds). The Action implementation is in the [Admin Service Event Handler](srv/src/main/java/my/bookshop/handlers/AdminServiceHandler.java) +- Add annotations for [searchable elements](https://github.wdf.sap.corp/pages/cap/java/query-api#select) in the [Admin Service](srv/admin-service.cds) +- [Localized Messages](https://cap.cloud.sap/docs/java/indicating-errors) in the [Admin Service Event Handler](srv/src/main/java/my/bookshop/handlers/AdminServiceHandler.java) +- role- and instance-based restrictions in [AdminService](srv/admin-service.cds) and [ReviewService](srv/review-service.cds) +- Use of [`@cds.persistence.skip`](https://cap.cloud.sap/docs/advanced/hana#cdspersistenceskip) in [AdminService](srv/admin-service.cds) +- [Media Data](https://cap.cloud.sap/docs/guides/providing-services#media-data) processing in the [Admin Service Event Handler](srv/src/main/java/my/bookshop/handlers/AdminServiceHandler.java) + +User Interface related Features: + +- Support for [SAP Fiori Elements](https://cap.cloud.sap/docs/advanced/fiori) +- [SAP Fiori Draft based Editing](https://cap.cloud.sap/docs/advanced/fiori#draft-support) for [Books, Orders](srv/admin-service.cds) and [Reviews](srv/review-service.cds) +- [SAP Fiori annotations](https://cap.cloud.sap/docs/advanced/fiori#fiori-annotations) specific for [Browse Books](app/browse/fiori-service.cds), [Manage Books](app/admin/fiori-service.cds), [Manage Orders](app/orders/fiori-service.cds), [Manage Reviews](app/reviews/fiori-service.cds) and [common annotations](app/common.cds), which apply to all UI's +- UI Annotations for custom actions in the [Browse Books](app/browse/fiori-service.cds) and [Manage Books](app/admin/fiori-service.cds) UI, including annotations for a button and a popup +- [Value Help](https://cap.cloud.sap/docs/cds/annotations#odata) for [Books](app/orders/fiori-service.cds) and [Authors](app/common.cds) +- [Model Localization](https://cap.cloud.sap/docs/guides/i18n) for [English](app/_i18n/i18n.properties) and [German](app/_i18n/i18n_de.properties) language for static texts +- [Custom File Upload extension](app/admin/webapp/extension/Upload.js) which provides a button for uploading `CSV` files +- A simple Swagger UI for the CatalogService API at + +CDS Maven Plugin Features: + +- Install [Node.js](srv/pom.xml#L157) in the default version. +- Install a [configured version](pom.xml#L24) of [@sap/cds-dk](srv/pom.xml#L167). +- Execute arbitrary [CDS](srv/pom.xml#L177) commands. +- [Generate](srv/pom.xml#L195) Java POJOs for type-safe access to the CDS model. +- [Clean](srv/pom.xml#L150) project from artifacts of the previous build. + +# Getting Started + +The following sections describe how to set up, build, and run the project. + +## Prerequisites + +Make sure you have set up a development environment (that means, you’ve installed the CDS Compiler, Java, and Apache Maven) [as described here](https://cap.cloud.sap/docs/java/getting-started). + +## Clone Build & Run + +1. Clone the project: + + ```bash + git clone https://github.com/SAP-samples/cloud-cap-samples-java.git + ``` + +2. Build and run the application: + + ``` + mvn spring-boot:run + ``` + +> [!NOTE] +> Please note that some IDEs may interfere with their autobuild when launching the application from the CLI using Maven. Therefore, please ensure that no IDEs are running in parallel or launch the application natively from your preferred IDE as described below. + +3. Use the following links in the browser to check if everything works fine: + + - http://localhost:8080: This should show the automatically generated index page of served paths. + - http://localhost:8080/fiori.html: This is the actual bookshop application UI. + - http://localhost:8080/swagger/index.html: This is providing a Swagger UI for the CatalogService API. + +You'll start with a predefined stock of books as this procedure starts the bookshop application with a CSV-initialized in-memory H2 database. + +Two mock users in addition to the [default mock users](https://cap.cloud.sap/docs/java/security#preconfigured-mock-users) +are defined for local development: +- User: `user`, password: `user` to browse books +- User: `admin`, password: `admin` to manage books and orders + +## Using VS Code + +VS Code supports the project out-of-the-box, when using the [Extension Pack for Java](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack). +To launch the application in VS Code navigate to the `Application` class and click on `Run` or `Debug`. + +## Using Eclipse + +Use the following steps to import the project to Eclipse: + +1. Import the project using **File > Import > Existing Maven Projects**. + + Now, you should see the projects **bookshop** and **bookshop-parent** in the project/package explorer view. + +2. In Project Explorer, change the property "Package Presentation" from "Flat" to "Hierarchical" for better understanding. + +### Building and Running + +1. To **compile** the project, right-click the file `pom.xml` in the `bookshop-parent` project root folder and select +**Run as** > **Maven build**. + + In the following dialog, enter the string `clean install` into the field labeled with "Goals" and click "Run". + + Note: This step also compiles the CDS artifacts, thus repeat this once you made changes to the CDS model. This step also generates source files, therefore refresh the "bookshop" project in your IDE. + +2. To **run** the application, right-click the `bookshop` project root in the Package Explorer and select **Run as** > **Spring Boot App** (make sure you have [Spring Tools 4 installed](https://marketplace.eclipse.org/content/spring-tools-4-aka-spring-tool-suite-4)). + + This step creates a default Run Configuration named `Bookshop - Application` and starts the application afterwards. To go on with the next step, stop the application again. + +3. Then, set the default working directory by editing your Run Configuration via **Run** > **Run Configurations** > **Bookshop - Application**. On the tab **Arguments** change the default **Working Directory** to: + + ```${workspace_loc:bookshop-parent}``` + + Afterward, click **Run**. This step starts the applications `main` method located in `src/main/java/my/bookshop/Application.java`. + +## Using IntelliJ Idea (Community and Ultimate) + +IntelliJ can handle the project more or less out-of-the-box. Since some of the event handlers in the project rely on +the code generated from the CDS model the build path of the project (module) needs to be extended +with the folder containing the generated code. In order to add the generated code you need to add the 'gen' folder +to the build path: + +1. Open the project settings. +2. Navigate to the 'modules' section. +3. Select the srv/src/gen folder and mark it as 'sources'. +4. Save and leave the project settings. +5. Trigger a rebuild. + +After the generated code is considered by IntelliJ's build the application can be handled just as any other Spring Boot +application in IntelliJ. + +## Database Setup and Spring Profiles + +The application comes with two predefined profiles that determine how to run the application: `default`, and `cloud` (see `srv/src/main/resources/application.yaml`). + + +- The `default` profile specifies to use an in-memory H2 database. + The in-memory database is set up automatically during startup of the application and initialized with some example data from CSV files. + +- When deploying the application to Cloud Foundry, the CF Java Buildpack automatically configures the `cloud` Spring profile. + This profile doesn’t specify any datasource location. In that case CAP Java can automatically detect SAP HANA service bindings available in the environment. + +## API_BUSINESS_PARTNER Remote Service and Spring Profiles + +The behavior of the API_BUSINESS_PARTNER remote service is controlled using profiles (see `srv/src/main/resources/application.yaml`): + +- **Using mock data via internal service:** When using only the `default` profile (default when omitting any profile setting), the API_BUSINESS_PARTNER API is mocked as a local service using the mock data. + +- **Using mock data via internal service through OData:** With the `mocked` profile, all requests to the API_BUSINESS_PARTNER service will be routed through HTTP and OData to itself (`http://localhost:/api/API_BUSINESS_PARTNER/...`). This mode is similar to using a real remote destination, and such helps to prevent issues from differences in local service and remote service behavior. + +- **Using the sandbox environment:** You can access data from the [SAP API Business Hub sandbox](https://api.sap.com/api/API_BUSINESS_PARTNER/overview) with the `sandbox` profile. The API key needs to be provided with the environment variable `CDS_REMOTE_SERVICES_API_BUSINESS_PARTNER_HTTP_HEADERS_APIKEY` or in the respective section in [`application.yaml`](srv/src/main/resources/application.yaml). You can retrieve it by clicking on *Show API Key* on [this page](https://api.sap.com/api/API_BUSINESS_PARTNER/overview) after logging in. + +- **Using S/4HANA cloud or on-premise system:** With the `destination` profile, you can access data from a real S/4HANA system. You need to create a destination with name `s4-destination` and make sure that an instance of XSUAA and destination service are bound to your application. For an on-premise destination, you additionally need to bind the connectivity service and add an additional property `URL.headers.sap-client` with the S/4HANA client number to your destination. + +The profiles `sandbox` and `destination` can be combined with the `default` profile for [hybrid testing](https://cap.cloud.sap/docs/advanced/hybrid-testing) and with the `cloud` profile when deployed to the cloud. + +## Deploy to SAP Business Technology Platform, Cloud Foundry + +CAP Java applications can be deployed to the SAP Business Technology Platform either in single tenant or in multitenancy mode. See [Multitenancy in CAP Java](https://cap.cloud.sap/docs/java/multitenancy) for more information. + +Prerequisites: +- Install the [Cloud MTA Build Tool](https://sap.github.io/cloud-mta-build-tool/): `npm install -g mbt`. +- Install the [Cloud Foundry Command Line Interface](https://docs.cloudfoundry.org/cf-cli/install-go-cli.html). +- Get an SAP Business Technology Platform account to deploy the services and applications. +- [Create a SAP HANA Cloud Instance](https://developers.sap.com/tutorials/hana-cloud-deploying.html) in your SAP Business Technology Platform space. +- Ensure you have an entitlement for `SAP HANA Schemas & HDI Containers` with plan `hdi-shared` in the same space. +- Ensure you have provided an API Key for the sandbox environment as described in the previous section. + +> [!NOTE] +> Please note that some IDEs may interfere with their autobuild during the MTA build and thus lead to corrupt MTA build results. Therefore, please ensure that no IDEs are running in parallel with your MTA build. + +Deploy as Single Tenant Application: +- Rename `mta-single-tenant.yaml` to `mta.yaml` +- Run `mbt build` +- Run `cf login` +- Run `cf deploy mta_archives/bookshop_1.0.0.mtar` + +Deploy as Multitenant Application: +- Rename `mta-multi-tenant.yaml` to `mta.yaml` +- Run `mbt build` +- Run `cf login` +- Run `cf deploy mta_archives/bookshop-mt_1.0.0.mtar` +- Go to another subaccount in your global account, under subscriptions and subscribe to the application you deployed. +- Run `cf map-route bookshop-mt-app --hostname ---bookshop-mt-app` or create and bind the route manually. + +> [!NOTE] +> Please note that the route length is limited to 63 characters and can easily be exceeded. So keeping the app name and sub-account subdomain as short as possible will help you stay within length. + +Before you can access the UI using the (tenant-specific) URL to the bookshop(-mt)-app application, make sure to [Setup Authorizations in SAP Business Technology Platform](#setup-authorizations-in-sap-business-technology-platform). + +## Deploy to SAP Business Technology Platform, Kyma Runtime + +**TIP:** You can find more information in the [Deploy Your CAP Application on SAP BTP Kyma Runtime](https://developers.sap.com/mission.btp-deploy-cap-kyma.html) tutorial and in the [Deploy to Kyma/K8s](https://cap.cloud.sap/docs/guides/deployment/deploy-to-kyma) guide of the CAP documentation. + +### Preconditions + +- BTP Subaccount with Kyma Runtime +- BTP Subaccount with Cloud Foundry Space +- [HANA Cloud instance available](https://developers.sap.com/tutorials/hana-cloud-deploying.html) for your Cloud Foundry space +- BTP Entitlements for: *HANA HDI Services & Container* plan *hdi-shared*, *Launchpad Service* plan *standard* +- Container Registry (e.g. [Docker Hub](https://hub.docker.com/)) +- Command Line Tools: [`kubectl`](https://kubernetes.io/de/docs/tasks/tools/install-kubectl/), [`kubectl-oidc_login`](https://github.com/int128/kubelogin#setup), [`pack`](https://buildpacks.io/docs/tools/pack/), [`docker`](https://docs.docker.com/get-docker/), [`helm`](https://helm.sh/docs/intro/install/), [`cf`](https://docs.cloudfoundry.org/cf-cli/install-go-cli.html) +- Logged into Kyma Runtime (with `kubectl` CLI), Cloud Foundry space (with `cf` CLI) and Container Registry (with `docker login`) +- `@sap/cds-dk` >= 6.6.0 + +### Add Deployment Files + +CAP tooling provides you a Helm chart for deployment to Kyma. + +For single tenant deployment, replace the `requires` section in _`.cdsrc.json`_ with: + +``` + "requires": { + "auth": { + "kind": "xsuaa" + }, + "approuter": { + "kind": "cloudfoundry" + }, + "db": { + "kind": "hana-cloud" + } + }, +``` + +**In addition** remove `"profile": "with-mtx-sidecar"` from `.cdsrc.json` and delete the `mtx` folder in root. + +For multi tenant deployment, replace the `requires` section in _`.cdsrc.json`_ with: + +``` + "requires": { + "multitenancy": true, + "extensibility": true, + "toggles": true, + "auth": { + "kind": "xsuaa" + }, + "approuter": { + "kind": "cloudfoundry" + } + }, +``` + +Add the CAP Helm chart with the required features to this project: + +```bash +cds add helm +``` + +#### Use API_BUSSINESS_PARTNER Remote Service (optional, single tenant only) + +You can try the `API_BUSINESS_PARTNER` service with a real S/4HANA system with the following configuration: + +1. Create either an on-premise or cloud destination in your subaccount. + +2. Add configuration required for the destination service by executing the following command. + + ```bash + cds add destination + ``` + +3. Set the profiles `cloud` and `destination` active in your `values.yaml` file: + + ```yaml + srv: + ... + env: + SPRING_PROFILES_ACTIVE: cloud,destination + ``` + +4. For on-premise only: Add the connectivity service to your Helm chart: + + ```bash + cds add connectivity + ``` + + Note: `cds add helm` will not add configuration required to create a Connectivity Service Instance. This Service Instance should be created by the Kyma Cluster Administrator. For more information regarding configuration of Connectivity Instance, please check the [documentation](https://cap.cloud.sap/docs/guides/deployment/deploy-to-kyma#connectivity-service). + +*See also: [API_BUSINESS_PARTNER Remote Service and Spring Profiles](#api_business_partner-remote-service-and-spring-profiles)* + +### Prepare Kubernetes Namespace + +#### Create container registry secret + +Create a secret `container-registry` with credentials to access the container registry: + +``` +bash ./scripts/create-container-registry-secret.sh +``` + +The *Docker Server* is the full qualified hostname of your container registry. + +#### Create a HDI container / Service Manager Instance and a Secret + +This step is only required if you're using a BTP Trial account. If you're using a production or a free tier account then you can create HDI Container from Kyma directly by adding a [mapping to your Kyma namespace in your HANA Cloud Instance](https://blogs.sap.com/2022/12/15/consuming-sap-hana-cloud-from-the-kyma-environment/) and skip this step. + +##### Single Tenant + +``` +bash ./scripts/create-db-secret.sh bookshop-db +``` + +It will create a HDI container `bookshop-db` instance on your currently targeted Cloud Foundry space and a secret `bookshop-db` with the credentials in your current Kubernetes namespace. + +Make the following changes to your _`chart/values.yaml`_. + +```diff +srv: + bindings: + db: +- serviceInstanceName: hana ++ fromSecret: bookshop-db +... + +hana-deployer: + bindings: + hana: +- serviceInstanceName: hana ++ fromSecret: bookshop-db + +... +- hana: +- serviceOfferingName: hana +- servicePlanName: hdi-shared +``` + +Make the following changes to your _`chart/Chart.yaml`_. + +```diff +dependencies: + ... +- - name: service-instance +- alias: hana +- version: ">0.0.0" + ... +``` + +##### Multi Tenant + +``` +bash ./scripts/create-sm-secret.sh bookshop-sm +``` + +It will create a Service Manager `bookshop-sm` instance on your currently targeted Cloud Foundry space and a secret `bookshop-sm` with the credentials in your current Kubernetes namespace. + +Make the following changes to your _`chart/values.yaml`_. + +```diff +srv: + bindings: + service-manager: +- serviceInstanceName: service-manager ++ fromSecret: bookshop-sm +... + +sidecar: + bindings: + service-manager: +- serviceInstanceName: service-manager ++ fromSecret: bookshop-sm + +... +- service-manager: +- serviceOfferingName: service-manager +- servicePlanName: container +``` + +Make the following changes to your _`chart/Chart.yaml`_. + +```diff +dependencies: + ... +- - name: service-instance +- alias: service-manager +- version: ">0.0.0" + ... +``` + +### Build + +```bash +cds build --production +``` + +**Build image for CAP service:** + +```bash +mvn clean package -DskipTests=true +``` + +```bash +pack build ${YOUR_CONTAINER_REGISTRY:?}/bookshop-srv \ + --path srv/target/*-exec.jar \ + --buildpack gcr.io/paketo-buildpacks/sap-machine \ + --buildpack gcr.io/paketo-buildpacks/java \ + --builder paketobuildpacks/builder-jammy-base \ + --env SPRING_PROFILES_ACTIVE=cloud \ + --env BP_JVM_VERSION=17 +``` + +(Replace `${YOUR_CONTAINER_REGISTRY:?}` with the full-qualified hostname of your container registry) + +**Build Approuter Image:** + +```bash +pack build ${YOUR_CONTAINER_REGISTRY:?}/bookshop-approuter \ + --path app \ + --buildpack gcr.io/paketo-buildpacks/nodejs \ + --builder paketobuildpacks/builder-jammy-base \ + --env BP_NODE_RUN_SCRIPTS="" +``` + +**Build database deployer image (single tenant only):** + +```bash +pack build ${YOUR_CONTAINER_REGISTRY:?}/bookshop-hana-deployer \ + --path db \ + --buildpack gcr.io/paketo-buildpacks/nodejs \ + --builder paketobuildpacks/builder-jammy-base \ + --env BP_NODE_RUN_SCRIPTS="" +``` + +**Build sidecar image (multi tenant only):** + +```bash +pack build ${YOUR_CONTAINER_REGISTRY:?}/bookshop-sidecar \ + --path mtx/sidecar/gen \ + --buildpack gcr.io/paketo-buildpacks/nodejs \ + --builder paketobuildpacks/builder-jammy-base \ + --env BP_NODE_RUN_SCRIPTS="" +``` + +### Push container images + +You can push all the container images to your container registry, using: + +```bash +docker push ${YOUR_CONTAINER_REGISTRY:?}/bookshop-srv + +docker push ${YOUR_CONTAINER_REGISTRY:?}/bookshop-approuter +``` + +#### Single Tenant + +```bash +docker push ${YOUR_CONTAINER_REGISTRY:?}/bookshop-hana-deployer +``` + +#### Multi Tenant + +```bash +docker push ${YOUR_CONTAINER_REGISTRY:?}/bookshop-sidecar +``` + +### Configuration + +Make the following changes in the _`chart/values.yaml`_ file. + +1. Change value of `global.domain` key to your cluster domain. + +2. Replace `` in `xsuaa.parameters.oauth2-configuration.redirect-uris` with your cluster domain. + +3. Replace `` with your container registry. + +4. Make the following change to add backend destinations required by Approuter. + +```diff +- backendDestinations: {} ++ backendDestinations: ++ backend: ++ service: srv ++ mtx-api: ++ service: srv +``` + +5. Add your image registry secret created in [Create container registry secret](#create-container-registry-secret) step. + +```diff +global: + domain: null +- imagePullSecret: {} ++ imagePullSecret: ++ name: container-registry +``` + +6. If the application is deployed multiple times in the same cluster, make sure to adapt the values of `xsappname` and `appName` under `saasRegistryParameters` in `values/Chart.yaml` + +### Deployment + +Deploy the helm chart using the following command: + +#### Single Tenant + +```bash +helm install bookshop ./chart --set-file xsuaa.jsonParameters=xs-security.json +``` + +Before you can access the UI you should make sure to [Setup Authorizations in SAP Business Technology Platform](#setup-authorizations-in-sap-business-technology-platform). + +Click on the approuter url logged by the `helm install` to access the UI. + +#### Multi Tenant + +```bash +helm install bookshop ./chart --set-file xsuaa.jsonParameters=xs-security-mt.json +``` + +In case of multi tenant, you'll have to subscribe to the application from a different subaccount. You can follow the steps mentioned [here](https://cap.cloud.sap/docs/guides/deployment/as-saas#subscribe) to access the application. + +## Setup Authorizations in SAP Business Technology Platform + +To access services and UIs that require specific authorizations (e.g. `admin`) you need to assign a corresponding role and role collections to your user in SAP BTP Cockpit. + +1. For single-tenant applications open the subaccount where you deployed the `bookshop` application to. For multitenant applications open the subaccount where you subscribed to the `bookshop` application. +2. Navigate to *Security* -> *Roles* +3. Create a role with name `bookshop-admin` based on the `admin` role template of the `bookshop` application: + 1. Enter a Business Partner ID of your S/4 system as value for the `businessPartner` attribute. When using the sandbox environment use `10401010`. +4. Navigate to *Security* -> *Role Collections* +5. Create a new role collection `bookshop-admin`: + 1. Assign the `bookshop-admin` role to this role collection + 2. Assign the role collection to your user + +# Code Tour + +Take the [guided tour](.tours) in VS Code through our CAP Samples for Java and learn which CAP features are showcased by the different parts of the repository. Just install the [CodeTour extension](https://marketplace.visualstudio.com/items?itemName=vsls-contrib.codetour) for VS Code. + +# Get Support + +In case you have a question, find a bug, or otherwise need support, please use our [community](https://answers.sap.com/tags/9f13aee1-834c-4105-8e43-ee442775e5ce). See the documentation at [https://cap.cloud.sap](https://cap.cloud.sap) for more details about CAP. + +# License + +Copyright (c) 2022 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](LICENSES/Apache-2.0.txt) file. diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/_i18n/i18n.properties b/app/multi-tenant/central-space/cloud-cap-samples-java/app/_i18n/i18n.properties new file mode 100644 index 000000000..4fa82a6fd --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/_i18n/i18n.properties @@ -0,0 +1,115 @@ +Customer = Customer +CreatedBy = Created By +Date = Date +Created = Created +Modified = Modified +ModifiedBy = Modified By +General = General +Details = Details +Admin = Administrative + +ID = ID +Currency = Currency + +Books = Books +Book = Book +Title = Title +Stock = Stock +Price = Price +Description = Description +BookPrice = Book Price +AddToOrder = Add to Order + +Authors = Authors +Author = Author +AuthorID = Author ID +Name = Name +AuthorName = Author's Name +DateOfBirth = Date of Birth +DateOfDeath = Date of Death +PlaceOfBirth = Place of Birth +PlaceOfDeath = Place of Death + +Order = Order +Orders = Orders +OrderNumber = Order Number +Total = Order Value + +OrderItem = Order Item +OrderItems = Order Items +Quantity = Quantity +Amount = Amount + +ShippingAddress = Shipping Address +ShippingAddresses = Shipping Addresses +CityName = City Name +HouseNumber = House Number +StreetName = Street Name +PostalCode = Postal Code +Country = Country +AddressID = Address ID +BusinessPartner = Contact + +Locale = Language + +Reviews = Reviews +Review = Review +Rating = Rating +Subject = Subject +Date = Date + +User = User +Text = Text +Image = Image +Genres = Genres +Genre = Genre + +AddReview = Add Review + +Notes = Notes +Note = Note +ISBN = ISBN + +reference = Reference +references = References + +#XFLD,50: Label for a section +Chapters=Chapters + +#XFLD,120: Label for entity +Chapter=Chapter + +#XFLD,120: Label for a field +ChapterTitle=Chapter Title + +#XFLD,120: Label for a field +ChapterType=Chapter Type + +#XFLD,50: Label for a section +Pages=Pages + +#XFLD,120: Label for entity +Page=Page + +#XFLD,120: Label for a field +PageTitle=Page Title + +#XFLD,120: Label for a field +PageType=Page Type + +#XFLD,50: Label for a section +Footnotes=Footnotes + +#XFLD,120: Label for a field +Description=Description + +#XFLD,120: Label for a field +URL=URL + +#XFLD,50: Label for a section +GeneralInformation=General Information + +#XFLD,50: Label for a section +Attachments=Attachments +uploadStatus=Upload Status +type=Type \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/_i18n/i18n_de.properties b/app/multi-tenant/central-space/cloud-cap-samples-java/app/_i18n/i18n_de.properties new file mode 100644 index 000000000..5bb11d0f2 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/_i18n/i18n_de.properties @@ -0,0 +1,71 @@ +Customer = Kunde +CreatedBy = Angelegt von +Date = Datum +Created = Angelegt +Modified = Bearbeitet +ModifiedBy = Bearbeitet von +General = Generelles +Details = Details +Admin = Administratives + +ID = ID +Currency = W\u00E4hrung + +Books = B\u00FCcher +Book = Buch +Title = Titel +Stock = Bestand +Price = Preis +Description = Beschreibung +BookPrice = Buchpreis +AddToOrder = Zu Bestellung hinzuf\u00FCgen + +Authors = Autor +Author = Autor +AuthorID = ID des Autors +Name = Name +AuthorName = Name des Autors +DateOfBirth = Geburtsdatum +DateOfDeath = Sterbedatum +PlaceOfBirth = Geburtsort +PlaceOfDeath = Sterbeort + +Order = Bestellung +Orders = Bestellungen +OrderNumber = Bestellungsnummer +Total = Bestellungswert + +OrderItem = Bestellungseintrag +OrderItems = Bestellungseintr\u00E4ge +Quantity = Menge +Amount = Wert + +ShippingAddress = Lieferaddresse +ShippingAddresses = Lieferaddressen +CityName = Stadt +HouseNumber = Hausnummer +StreetName = Stra\u00DFe +PostalCode = Postleitzahl +Country = Land +AddressID = ID der Addresse +BusinessPartner = Kontakt + +Locale = Sprache + +Reviews = Rezensionen +Review = Rezension +Rating = Bewertung +Subject = Betreff +Date = Datum + +User = Benutzer +Text = Text +Image = Bild +Genres = Genre +Genre = Genre + +AddReview = Rezension hinzufügen + +Notes = Notizen +Note = Notiz +ISBN = ISBN diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/fiori-service.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/fiori-service.cds new file mode 100644 index 000000000..51887f318 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/fiori-service.cds @@ -0,0 +1,83 @@ +using NotesService from '../../srv/notes-mashup'; + +annotate NotesService.Addresses with @(UI : { + LineItem : [ + { + Value : businessPartner, + Label : '{i18n>BusinessPartner}' + }, + { + Value : ID, + Label : '{i18n>ID}' + }, + { + Value : street, + Label : '{i18n>StreetName}' + }, + { + Value : city, + Label : '{i18n>CityName}' + }, + { + Value : country, + Label : '{i18n>Country}' + } + ], + HeaderInfo : { + TypeName : '{i18n>ShippingAddress}', + TypeNamePlural : '{i18n>ShippingAddresses}', + Title : {Value : ID}, + Description : {Value : businessPartner}, + }, + PresentationVariant : { + Text : 'Default', + Visualizations : ['@UI.LineItem'] + }, + Facets : [ + { + $Type : 'UI.ReferenceFacet', + Target : '@UI.FieldGroup#Address', + Label : '{i18n>ShippingAddress}', + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>Notes}', + Target : 'notes/@UI.LineItem' + } + ], + FieldGroup #Address : {Data : [ + { + Value : street, + Label : '{i18n>StreetName}' + }, + { + Value : houseNumber, + Label : '{i18n>HouseNumber}' + }, + { + Value : postalCode, + Label : '{i18n>PostalCode}' + }, + { + Value : city, + Label : '{i18n>CityName}' + }, + { + Value : country, + Label : '{i18n>Country}' + } + ]}, +}) { + businessPartner + @title : '{i18n>BusinessPartner}' + @UI.HiddenFilter; + ID + @title : '{i18n>ID}' + @UI.HiddenFilter; + street + @title : '{i18n>StreetName}'; + city + @title : '{i18n>CityName}'; + country + @title : '{i18n>Country}'; +}; diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/package.json b/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/package.json new file mode 100644 index 000000000..8e75334b8 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/package.json @@ -0,0 +1,12 @@ +{ + "name": "addresses", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/webapp/Component.js b/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/webapp/Component.js new file mode 100644 index 000000000..5def6d128 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/webapp/Component.js @@ -0,0 +1,3 @@ +sap.ui.define(["sap/fe/core/AppComponent"], ac => ac.extend("addresses.Component", { + metadata:{ manifest:'json' } +})) diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/webapp/i18n/i18n.properties b/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/webapp/i18n/i18n.properties new file mode 100644 index 000000000..32c07eed7 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/webapp/i18n/i18n.properties @@ -0,0 +1,2 @@ +appTitle=Show Shipping Addresses +appDescription=Show Shipping Addresses - Sample Application diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/webapp/i18n/i18n_de.properties b/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/webapp/i18n/i18n_de.properties new file mode 100644 index 000000000..a150555b3 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/webapp/i18n/i18n_de.properties @@ -0,0 +1,2 @@ +appTitle=Zeige Lieferaddressen +appDescription=Zeige Lieferaddressen - Beispielanwendung diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/webapp/index.html b/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/webapp/index.html new file mode 100644 index 000000000..a59fa7d2c --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/webapp/index.html @@ -0,0 +1,35 @@ + + + + + + + Show Shipping Addresses + + + + +
+ + diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/webapp/manifest.json b/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/webapp/manifest.json new file mode 100644 index 000000000..5266df52f --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/addresses/webapp/manifest.json @@ -0,0 +1,142 @@ +{ + "_version": "1.8.0", + "sap.app": { + "id": "addresses", + "type": "application", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + }, + "dataSources": { + "NotesService": { + "uri": "/api/notes/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + }, + "-sourceTemplate": { + "id": "ui5template.basicSAPUI5ApplicationProject", + "-id": "ui5template.smartTemplate", + "-version": "1.40.12" + }, + "crossNavigation": { + "inbounds": { + "Addresses-show": { + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "semanticObject": "Addresses", + "action": "show" + } + } + } + }, + "sap.ui5": { + "dependencies": { + "libs": { + "sap.fe.templates": {} + } + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "i18n/i18n.properties" + }, + "": { + "dataSource": "NotesService", + "settings": { + "synchronizationMode": "None", + "operationMode": "Server", + "autoExpandSelect" : true, + "earlyRequests": true, + "groupProperties": { + "default": { + "submit": "Auto" + } + } + } + } + }, + "routing": { + "routes": [ + { + "pattern": ":?query:", + "name": "AddressesList", + "target": "AddressesList" + }, + { + "pattern": "Addresses({key}):?query:", + "name": "AddressesDetails", + "target": "AddressesDetails" + }, + { + "pattern": "Addresses({key})/notes({key2}):?query:", + "name": "NotesDetails", + "target": "NotesDetails" + } + ], + "targets": { + "AddressesList": { + "type": "Component", + "id": "AddressesList", + "name": "sap.fe.templates.ListReport", + "options": { + "settings" : { + "entitySet" : "Addresses", + "navigation" : { + "Addresses" : { + "detail" : { + "route" : "AddressesDetails" + } + } + } + } + } + }, + "AddressesDetails": { + "type": "Component", + "id": "AddressesDetails", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet" : "Addresses", + "navigation" : { + "notes" : { + "detail" : { + "route" : "NotesDetails" + } + } + } + } + } + }, + "NotesDetails": { + "type": "Component", + "id": "NotesDetails", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet": "Notes" + } + } + } + } + }, + "contentDensities": { + "compact": true, + "cozy": true + } + }, + "sap.ui": { + "technology": "UI5", + "fullWidth": false + }, + "sap.fiori": { + "registrationIds": [], + "archeType": "transactional" + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/fiori-service.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/fiori-service.cds new file mode 100644 index 000000000..8dd68120a --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/fiori-service.cds @@ -0,0 +1,401 @@ +/* + Annotations for the Manage Books App +*/ + +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>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' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'AttachmentsFacet', + Label : '{i18n>attachments}', + Target : 'attachments/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'ReferencesFacet', + Label : 'References', + Target : 'references/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'FootNotesFacet', + Label : 'FootNotes', + Target : 'footnotes/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>Chapters}', + ID : 'i18nChapters', + Target : 'cHapters/@UI.LineItem#i18nChapters', + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>Pages}', + ID : 'i18nPages', + Target : 'pages/@UI.LineItem#i18nPages', + }, + ], + 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 my.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 + } +} + +annotate AdminService.Books actions { + @( + Common.SideEffects : { + TargetProperties : ['_it/order_ID'], + TargetEntities : [_it] + }, + cds.odata.bindingparameter.name : '_it' + ) + addToOrder(order_ID @( + title : '{i18n>Order}', + Common : {ValueListMapping : { + Label : '{i18n>Orders}', + CollectionPath : 'Orders', + Parameters : [ + { + $Type : 'Common.ValueListParameterInOut', + LocalDataProperty : order_ID, + ValueListProperty : 'ID' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'OrderNo' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'createdBy' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'createdAt' + } + ], + }} + ), + quantity @title : '{i18n>Quantity}' + ) +} + +annotate AdminService.Books.attachments with { + customProperty1 @Common.ValueListWithFixedValues; +} +annotate AdminService.Books.references with { + customProperty1 @Common.ValueListWithFixedValues; +} +annotate AdminService.Books.footnotes with { + customProperty1 @Common.ValueListWithFixedValues; +} + +// Chapters annotations +annotate AdminService.Chapters with @title : '{i18n>Chapter}'; + +annotate AdminService.Books.chapters with @( + title : '{i18n>Chapters}' +); + +annotate AdminService.Chapters with @( + UI.LineItem : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>ChapterTitle}', + }, + { + $Type : 'UI.DataField', + Value : chapterType, + Label : '{i18n>ChapterType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + ], + UI.LineItem #i18nChapters : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>ChapterTitle}', + }, + { + $Type : 'UI.DataField', + Value : chapterType, + Label : '{i18n>ChapterType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + ] +); + +annotate AdminService.Chapters with @( + UI.HeaderInfo : { + Title : { + $Type : 'UI.DataField', + Value : title, + }, + TypeName : '{i18n>Chapter}', + TypeNamePlural : '{i18n>Chapters}', + Description : { + $Type : 'UI.DataField', + Value : description, + }, + } +); + +annotate AdminService.Chapters with @( + UI.FieldGroup #GeneratedGroup1 : { + $Type : 'UI.FieldGroupType', + Data : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>ChapterTitle}', + }, + { + $Type : 'UI.DataField', + Value : chapterType, + Label : '{i18n>ChapterType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + { + $Type : 'UI.DataField', + Value : url, + Label : '{i18n>URL}', + }, + ], + }, + UI.Facets : [ + { + $Type : 'UI.ReferenceFacet', + ID : 'GeneratedFacet1', + Label : '{i18n>GeneralInformation}', + Target : '@UI.FieldGroup#GeneratedGroup1', + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'AttachmentsFacet', + Label : '{i18n>attachments}', + Target : 'attachments/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'ReferencesFacet', + Label : '{i18n>references}', + Target : 'references/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'FootnotesFacet', + Label : '{i18n>Footnotes}', + Target : 'footnotes/@UI.LineItem' + } + ] +); + +////////// + +// Pages annotations +annotate AdminService.Pages with @title : '{i18n>Page}'; + +annotate AdminService.Books.pages with @( + title : '{i18n>Pages}' +); + +annotate AdminService.Pages with @( + UI.LineItem : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>PageTitle}', + }, + { + $Type : 'UI.DataField', + Value : pageType, + Label : '{i18n>PageType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + ], + UI.LineItem #i18nPages : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>PageTitle}', + }, + { + $Type : 'UI.DataField', + Value : pageType, + Label : '{i18n>PageType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + ] +); + +annotate AdminService.Pages with @( + UI.HeaderInfo : { + Title : { + $Type : 'UI.DataField', + Value : title, + }, + TypeName : '{i18n>Page}', + TypeNamePlural : '{i18n>Pages}', + Description : { + $Type : 'UI.DataField', + Value : description, + }, + } +); + +annotate AdminService.Pages with @( + UI.FieldGroup #GeneratedGroup1 : { + $Type : 'UI.FieldGroupType', + Data : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>PageTitle}', + }, + { + $Type : 'UI.DataField', + Value : pageType, + Label : '{i18n>PageType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + { + $Type : 'UI.DataField', + Value : url, + Label : '{i18n>URL}', + }, + ], + }, + UI.Facets : [ + { + $Type : 'UI.ReferenceFacet', + ID : 'GeneratedFacet1', + Label : '{i18n>GeneralInformation}', + Target : '@UI.FieldGroup#GeneratedGroup1', + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'AttachmentsFacet', + Label : '{i18n>attachments}', + Target : 'attachments/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'ReferencesFacet', + Label : '{i18n>references}', + Target : 'references/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'FootnotesFacet', + Label : '{i18n>Footnotes}', + Target : 'footnotes/@UI.LineItem' + } + ] +); \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/package.json b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/package.json new file mode 100644 index 000000000..17db44b07 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/package.json @@ -0,0 +1,12 @@ +{ + "name": "admin", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/Component.js b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/Component.js new file mode 100644 index 000000000..332ed12eb --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/Component.js @@ -0,0 +1,3 @@ +sap.ui.define(["sap/fe/core/AppComponent"], ac => ac.extend("admin.Component", { + metadata:{ manifest:'json' } +})) diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/books/controller/custom.controller.js b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/books/controller/custom.controller.js new file mode 100644 index 000000000..a7fd5a2a7 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/books/controller/custom.controller.js @@ -0,0 +1,33 @@ +sap.ui.define( + [ + "sap/ui/core/mvc/ControllerExtension", + "sap/m/library" + ], + function (ControllerExtension,library) { + "use strict"; + + return ControllerExtension.extend("books.controller.custom", { + onRowPress: function(oContext) { + this.base.editFlow + .invokeAction("AdminService.openAttachment", { + contexts: oContext.getParameter("bindingContext") + }) + .then(function (res) { + let odataurl = ""; + if(res.getObject().value == "None") { + const lastSlashIndex = res.oModel.getServiceUrl().lastIndexOf('/'); + let str = res.oModel.getServiceUrl(); + if (lastSlashIndex !== -1) { + str = str.substring(0, lastSlashIndex) + str.substring(lastSlashIndex + 1); + } + odataurl = str+res.oBinding.oContext.sPath+"/content"; + } else { + odataurl = res.getObject().value; + } + library.URLHelper.redirect(odataurl, true); + + }); + } + }); + } +); \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/controller/custom.controller.js b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/controller/custom.controller.js new file mode 100644 index 000000000..3786a0e9f --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/controller/custom.controller.js @@ -0,0 +1,141 @@ +sap.ui.define( + [ + "sap/ui/core/mvc/ControllerExtension", + "sap/m/library", + "sap/ui/core/format/DateFormat" + ], + function (ControllerExtension, library, DateFormat) { + "use strict"; + const ChangeCategoryEnum = { + created: "Created", + updated: "Changed" + // Add more mappings as needed + }; + + return ControllerExtension.extend("admin.controller.custom", { + isDownloadEnabled: function(oBindingContext, aSelectedContexts) { + if (!aSelectedContexts || aSelectedContexts.length === 0) { + return false; + } + return !aSelectedContexts.some(function(oContext) { + return oContext.getProperty("mimeType") === "application/internet-shortcut"; + }); + }, + onRowPress: function(oContext) { + this.base.editFlow + .invokeAction("AdminService.openAttachment", { + contexts: oContext.getParameter("bindingContext") + }) + .then(function (res) { + let odataurl = ""; + if(res.getObject().value == "None") { + const lastSlashIndex = res.oModel.getServiceUrl().lastIndexOf('/'); + let str = res.oModel.getServiceUrl(); + if (lastSlashIndex !== -1) { + str = str.substring(0, lastSlashIndex) + str.substring(lastSlashIndex + 1); + } + odataurl = str+res.oBinding.oContext.sPath+"/content"; + } else { + odataurl = res.getObject().value; + } + library.URLHelper.redirect(odataurl, true); + + }); + }, + onChangelogPress: function(oContext, aSelectedContexts) { + var that =this; + this.base.editFlow + .invokeAction("AdminService.changelog", { + contexts: aSelectedContexts + }) + .then(function (res) { + console.log("Result",res[0].value.getObject().value); + that.updateChangeLogInPropertiesModel(res[0].value.getObject().value); + }); + }, + updateChangeLogInPropertiesModel: function (oChangeLogsForObjectResponse) { + const aChangeLogs = []; + const fileName = JSON.parse(oChangeLogsForObjectResponse).filename; + console.log("Filename: ", fileName); + const aChangeLogsObject = JSON.parse(oChangeLogsForObjectResponse)["changeLogs"]; + console.log("ChangeLogsObject:\n", aChangeLogsObject); + // Take latest changes at the top + for (let idx = aChangeLogsObject.length - 1; idx >= 0; idx--) { + const oChangeLogEntry = aChangeLogsObject[idx]; + const sLastModifiedBy = oChangeLogEntry["user"]; + const sChangeType = oChangeLogEntry["operation"]; + const sChangeTime = oChangeLogEntry["time"]; + let dateTimeFormat = DateFormat.getDateTimeInstance(sap.ui.getCore().getConfiguration().getLocale()); + let changedDate = new Date(sChangeTime); + let changedTime = changedDate?dateTimeFormat.format(new Date(changedDate)) : "" ; + const oChangeLog = { + changedOn: changedTime, + changedBy: sLastModifiedBy, + changeType: ChangeCategoryEnum[sChangeType] + }; + aChangeLogs.push(oChangeLog); + console.log("ChangeLog:\n", oChangeLog); + } + + this.logFragment= this.base.getExtensionAPI().loadFragment({ + name: "admin.fragments.changelog", + controller: this + }); + var that = this; + this.logFragment.then(function (dialog) { + if(dialog){ + dialog.attachEventOnce("afterClose", function () { + dialog.destroy(); + }); + var oModel = new sap.ui.model.json.JSONModel(); + oModel.setSizeLimit(100000); + oModel.setData(aChangeLogs); + that.getView().setModel(oModel, "changelog"); + dialog.setTitle(fileName); + dialog.open() + } + }); + }, + close: function (closeBtn) { + closeBtn.getSource().getParent().close(); + }, + onDownloadPress: function(oContext, aSelectedContexts) { + var sIds = aSelectedContexts.map(function (oCtx) { + return oCtx.getObject().ID; + }).join(","); + this.base.editFlow + .invokeAction("AdminService.downloadSelectedAttachments", { + contexts: aSelectedContexts[0], + parameterValues: [{ name: "ids", value: sIds }], + skipParameterDialog: true + }) + .then(function (res) { + var sJsonResponse = res.getObject().value; + var aEntries = JSON.parse(sJsonResponse); + aEntries.forEach(function (oEntry) { + if (oEntry.status === "success") { + if (oEntry.linkUrl) { + window.open(oEntry.linkUrl, "_blank"); + } else if (oEntry.content) { + var byteString = atob(oEntry.content); + var aBytes = new Uint8Array(byteString.length); + for (var i = 0; i < byteString.length; i++) { + aBytes[i] = byteString.charCodeAt(i); + } + var oBlob = new Blob([aBytes], { type: oEntry.mimeType || "application/octet-stream" }); + var sUrl = URL.createObjectURL(oBlob); + var oLink = document.createElement("a"); + oLink.href = sUrl; + oLink.download = oEntry.fileName || "download"; + document.body.appendChild(oLink); + oLink.click(); + document.body.removeChild(oLink); + URL.revokeObjectURL(sUrl); + } + } + }); + }); + } + }); + } +); diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/extension/Upload.js b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/extension/Upload.js new file mode 100644 index 000000000..bc1ce3d52 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/extension/Upload.js @@ -0,0 +1,119 @@ +sap.ui.define( + ["sap/m/MessageBox", "sap/m/MessageToast"], + function (MessageBox, MessageToast) { + "use strict"; + + function _createUploadController(oExtensionAPI) { + var oUploadDialog; + + function setOkButtonEnabled(bOk) { + oUploadDialog && oUploadDialog.getBeginButton().setEnabled(bOk); + } + + function setDialogBusy(bBusy) { + oUploadDialog.setBusy(bBusy) + } + + function closeDialog() { + oUploadDialog && oUploadDialog.close() + } + + function showError(sMessage) { + MessageBox.error(sMessage || "Upload failed") + } + + // TODO: Better option for this? + function byId(sId) { + return sap.ui.core.Fragment.byId("uploadDialog", sId); + } + + return { + onBeforeOpen: function (oEvent) { + oUploadDialog = oEvent.getSource(); + oExtensionAPI.addDependent(oUploadDialog); + }, + + onAfterClose: function (oEvent) { + oExtensionAPI.removeDependent(oUploadDialog); + oUploadDialog.destroy(); + oUploadDialog = undefined; + }, + + onOk: function (oEvent) { + setDialogBusy(true) + + var oFileUploader = byId("uploader") + + oFileUploader + .checkFileReadable() + .then(function () { + oFileUploader.upload(); + }) + .catch(function (error) { + showError("The file cannot be read."); + setDialogBusy(false) + }) + }, + + onCancel: function (oEvent) { + closeDialog(); + }, + + onTypeMismatch: function (oEvent) { + var sSupportedFileTypes = oEvent + .getSource() + .getFileType() + .map(function (sFileType) { + return "*." + sFileType; + }) + .join(", "); + + showError( + "The file type *." + + oEvent.getParameter("fileType") + + " is not supported. Choose one of the following types: " + + sSupportedFileTypes + ); + }, + + onFileAllowed: function (oEvent) { + setOkButtonEnabled(true) + }, + + onFileEmpty: function (oEvent) { + setOkButtonEnabled(false) + }, + + onUploadComplete: function (oEvent) { + var iStatus = oEvent.getParameter("status"); + var oFileUploader = oEvent.getSource() + + oFileUploader.clear(); + setOkButtonEnabled(false) + setDialogBusy(false) + + if (iStatus >= 400) { + var oRawResponse = JSON.parse(oEvent.getParameter("responseRaw")); + showError(oRawResponse && oRawResponse.error && oRawResponse.error.message); + } else { + MessageToast.show("Uploaded successfully"); + oExtensionAPI.refresh() + closeDialog(); + } + } + }; + } + + return { + showUploadDialog: function (oBindingContext, aSelectedContexts) { + this.loadFragment({ + id: "uploadDialog", + name: "admin.extension.UploadDialog", + controller: _createUploadController(this) + }).then(function (oDialog) { + oDialog.open(); + }); + } + }; + } +); \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/extension/UploadDialog.fragment.xml b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/extension/UploadDialog.fragment.xml new file mode 100644 index 000000000..4edaded54 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/extension/UploadDialog.fragment.xml @@ -0,0 +1,27 @@ + + + + + + + + \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/fragments/changelog.fragment.xml b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/fragments/changelog.fragment.xml new file mode 100644 index 000000000..ac02a9275 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/fragments/changelog.fragment.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+ + +
+
diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/i18n/i18n.properties b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/i18n/i18n.properties new file mode 100644 index 000000000..6615b898c --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/i18n/i18n.properties @@ -0,0 +1,2 @@ +appTitle=Manage Books +appDescription=Manage Books - Sample Application diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/i18n/i18n_de.properties b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/i18n/i18n_de.properties new file mode 100644 index 000000000..69ef58862 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/i18n/i18n_de.properties @@ -0,0 +1,2 @@ +appTitle=Administriere B\u00FCcher +appDescription=Administriere B\u00FCcher - Beispielanwendung diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/index.html b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/index.html new file mode 100644 index 000000000..4a5cae947 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/index.html @@ -0,0 +1,35 @@ + + + + + + + Manage Books + + + + +
+ + diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/manifest.json b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/manifest.json new file mode 100644 index 000000000..bd34e5ebe --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/admin/webapp/manifest.json @@ -0,0 +1,487 @@ +{ + "_version": "1.8.0", + "sap.app": { + "id": "admin", + "type": "application", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + }, + "dataSources": { + "AdminService": { + "uri": "/api/admin/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + }, + "-sourceTemplate": { + "id": "ui5template.basicSAPUI5ApplicationProject", + "-id": "ui5template.smartTemplate", + "-version": "1.40.12" + }, + "crossNavigation": { + "inbounds": { + "Books-manage": { + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "semanticObject": "Books", + "action": "manage" + } + } + } + }, + "sap.ui5": { + "dependencies": { + "libs": { + "sap.fe.templates": {} + } + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "i18n/i18n.properties" + }, + "": { + "dataSource": "AdminService", + "settings": { + "synchronizationMode": "None", + "operationMode": "Server", + "autoExpandSelect": true, + "earlyRequests": true, + "groupProperties": { + "default": { + "submit": "Auto" + } + } + } + } + }, + "routing": { + "routes": [ + { + "pattern": ":?query:", + "name": "BooksList", + "target": "BooksList" + }, + { + "pattern": "Books({key}):?query:", + "name": "BooksDetails", + "target": "BooksDetails" + }, + { + "pattern": "Books({key})/author({key2}):?query:", + "name": "AuthorsDetails", + "target": "AuthorsDetails" + }, + { + "pattern": "Books({key})/cHapters({key2}):?query:", + "name": "ChaptersObjectPage", + "target": "ChaptersObjectPage" + }, + { + "pattern": "Books({key})/pages({key2}):?query:", + "name": "PagesObjectPage", + "target": "PagesObjectPage" + } + ], + "targets": { + "BooksList": { + "type": "Component", + "id": "BooksList", + "name": "sap.fe.templates.ListReport", + "options": { + "settings": { + "entitySet": "Books", + "navigation": { + "Books": { + "detail": { + "route": "BooksDetails" + } + }, + "Chapters": { + "detail": { + "route": "ChaptersObjectPage" + } + }, + "Pages": { + "detail": { + "route": "PagesObjectPage" + } + } + }, + "content": { + "header": { + "actions": { + "upload": { + "press": "admin.extension.Upload.showUploadDialog", + "text": "Import Books" + } + } + } + } + } + } + }, + "BooksDetails": { + "type": "Component", + "id": "BooksDetailsList", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings": { + "entitySet": "Books", + "navigation": { + "Authors": { + "detail": { + "route": "AuthorsDetails" + } + }, + "Chapters": { + "detail": { + "route": "ChaptersObjectPage" + } + }, + "Pages": { + "detail": { + "route": "PagesObjectPage" + } + } + }, + "controlConfiguration": { + "attachments/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.admin.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.admin.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.admin.controller.custom.isDownloadEnabled", + "press": ".extension.admin.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "references/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.admin.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.admin.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.admin.controller.custom.isDownloadEnabled", + "press": ".extension.admin.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "footnotes/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.admin.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.admin.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.admin.controller.custom.isDownloadEnabled", + "press": ".extension.admin.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + } + } + } + } + }, + "AuthorsDetails": { + "type": "Component", + "id": "AuthorsDetailsList", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings": { + "entitySet": "Authors" + } + } + }, + "ChaptersObjectPage": { + "type": "Component", + "id": "ChaptersObjectPage", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings": { + "editableHeaderContent": false, + "entitySet": "Chapters", + "controlConfiguration": { + "attachments/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.admin.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.admin.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.admin.controller.custom.isDownloadEnabled", + "press": ".extension.admin.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "references/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.admin.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.admin.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.admin.controller.custom.isDownloadEnabled", + "press": ".extension.admin.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "footnotes/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.admin.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.admin.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.admin.controller.custom.isDownloadEnabled", + "press": ".extension.admin.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + } + } + } + } + }, + "PagesObjectPage": { + "type": "Component", + "id": "PagesObjectPage", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings": { + "editableHeaderContent": false, + "entitySet": "Pages", + "navigation": {}, + "controlConfiguration": { + "attachments/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.admin.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.admin.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.admin.controller.custom.isDownloadEnabled", + "press": ".extension.admin.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "references/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.admin.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.admin.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.admin.controller.custom.isDownloadEnabled", + "press": ".extension.admin.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "footnotes/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.admin.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.admin.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.admin.controller.custom.isDownloadEnabled", + "press": ".extension.admin.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + } + } + } + } + } + } + }, + "extends": { + "extensions": { + "sap.ui.controllerExtensions": { + "sap.fe.templates.ObjectPage.ObjectPageController#admin::BooksDetailsList": { + "controllerName": "admin.controller.custom" + }, + "sap.fe.templates.ObjectPage.ObjectPageController#admin::ChaptersObjectPage": { + "controllerName": "admin.controller.custom" + }, + "sap.fe.templates.ObjectPage.ObjectPageController#admin::PagesObjectPage": { + "controllerName": "admin.controller.custom" + } + } + } + }, + "contentDensities": { + "compact": true, + "cozy": true + } + }, + "sap.ui": { + "technology": "UI5", + "fullWidth": false + }, + "sap.fiori": { + "registrationIds": [], + "archeType": "transactional" + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/appconfig/fioriSandboxConfig.json b/app/multi-tenant/central-space/cloud-cap-samples-java/app/appconfig/fioriSandboxConfig.json new file mode 100644 index 000000000..1dc45ef87 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/appconfig/fioriSandboxConfig.json @@ -0,0 +1,185 @@ +{ + "services": { + "LaunchPage": { + "adapter": { + "config": { + "catalogs": [], + "groups": [ + { + "id": "Bookshop", + "title": "Bookshop", + "isPreset": true, + "isVisible": true, + "isGroupLocked": false, + "tiles": [ + { + "id": "browse-books", + "tileType": "sap.ushell.ui.tile.StaticTile", + "properties": { + "targetURL": "#Books-display", + "title": "Browse Books", + "description": "Find your favorite book" + } + } + ] + }, + { + "id": "Administration", + "title": "Administration", + "isPreset": true, + "isVisible": true, + "isGroupLocked": false, + "tiles": [ + { + "id": "manage-books", + "tileType": "sap.ushell.ui.tile.StaticTile", + "properties": { + "targetURL": "#Books-manage", + "title": "Manage Books", + "description": "Add/edit/delete books" + } + }, + { + "id": "manage-orders", + "tileType": "sap.ushell.ui.tile.StaticTile", + "properties": { + "targetURL": "#Orders-manage", + "title": "Manage Orders", + "description": "Find & manage orders" + } + }, + { + "id": "manage-reviews", + "tileType": "sap.ushell.ui.tile.StaticTile", + "properties": { + "targetURL": "#Reviews-manage", + "title": "Manage Reviews", + "description": "Add/edit/delete reviews" + } + } + ] + }, + { + "id": "Shipping", + "title": "Shipping", + "isPreset": true, + "isVisible": true, + "isGroupLocked": false, + "tiles": [ + { + "id": "manage-notes", + "tileType": "sap.ushell.ui.tile.StaticTile", + "properties": { + "targetURL": "#Notes-manage", + "title": "Manage Notes", + "description": "Read & create notes for addresses" + } + }, + { + "id": "show-addresses", + "tileType": "sap.ushell.ui.tile.StaticTile", + "properties": { + "targetURL": "#Addresses-display", + "title": "Show Shipping Addresses", + "description": "Find the right shipping address" + } + } + ] + } + ] + } + } + }, + "NavTargetResolution": { + "config": { + "enableClientSideTargetResolution": true + } + }, + "ClientSideTargetResolution": { + "adapter": { + "config": { + "inbounds": { + "browse-books": { + "semanticObject": "Books", + "action": "display", + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "resolutionResult": { + "applicationType": "SAPUI5", + "additionalInformation": "SAPUI5.Component=bookshop", + "url": "/browse/webapp" + } + }, + "manage-books": { + "semanticObject": "Books", + "action": "manage", + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "resolutionResult": { + "applicationType": "SAPUI5", + "additionalInformation": "SAPUI5.Component=admin", + "url": "/admin/webapp" + } + }, + "manage-orders": { + "semanticObject": "Orders", + "action": "manage", + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "resolutionResult": { + "applicationType": "SAPUI5", + "additionalInformation": "SAPUI5.Component=orders", + "url": "/orders/webapp" + } + }, + "manage-reviews": { + "semanticObject": "Reviews", + "action": "manage", + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "resolutionResult": { + "applicationType": "SAPUI5", + "additionalInformation": "SAPUI5.Component=reviews", + "url": "/reviews/webapp" + } + }, + "manage-notes": { + "semanticObject": "Notes", + "action": "manage", + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "resolutionResult": { + "applicationType": "SAPUI5", + "additionalInformation": "SAPUI5.Component=notes", + "url": "/notes/webapp" + } + }, + "show-addresses": { + "semanticObject": "Addresses", + "action": "display", + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "resolutionResult": { + "applicationType": "SAPUI5", + "additionalInformation": "SAPUI5.Component=addresses", + "url": "/addresses/webapp" + } + } + } + } + } + } + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/fiori-service.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/fiori-service.cds new file mode 100644 index 000000000..953c39dc2 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/fiori-service.cds @@ -0,0 +1,177 @@ +/* + Annotations for the Browse Books App +*/ + +using CatalogService from '../../srv/cat-service'; + +//////////////////////////////////////////////////////////////////////////// +// +// Books Object Page +// +annotate CatalogService.Books with @(UI : { + HeaderInfo : { + TypeName : '{i18n>Book}', + TypeNamePlural : '{i18n>Books}', + Title : {Value : title}, + Description : {Value : author.name} + }, + Identification : [ + {Value : title}, + { + $Type : 'UI.DataFieldForAction', + Label : '{i18n>AddReview}', + Action : 'CatalogService.addReview' + } + ], + PresentationVariant : { + Text : 'Default', + SortOrder : [{Property : title}], + Visualizations : ['@UI.LineItem'] + }, + SelectionFields : [ + author_ID, + genre_ID + ], + HeaderFacets : [ + { + $Type : 'UI.ReferenceFacet', + Target : '@UI.DataPoint#rating' + }, + { + $Type : 'UI.ReferenceFacet', + Target : '@UI.DataPoint#price' + } + ], + LineItem : [ + {Value : title}, + { + Value : author.name, + Label : '{i18n>Author}' + }, + { + Value : genre.name, + Label : '{i18n>Genre}' + }, + { + $Type : 'UI.DataFieldForAnnotation', + Target : '@UI.DataPoint#rating', + Label : '{i18n>Rating}' + }, + {Value : price}, + { + $Type : 'UI.DataFieldForAnnotation', + Label : '{i18n>AddReview}', + Target : '@UI.FieldGroup#AddReview' + } + ], + Facets : [ + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>General}', + Target : '@UI.FieldGroup#General' + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>Description}', + Target : '@UI.FieldGroup#Descr' + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>Reviews}', + Target : 'reviews/@UI.LineItem' + } + ], + FieldGroup #AddReview : {Data : [{ + $Type : 'UI.DataFieldForAction', + Label : '{i18n>AddReview}', + Action : 'CatalogService.addReview', + InvocationGrouping : #ChangeSet + }, ]}, + FieldGroup #General : {Data : [ + {Value : title}, + {Value : author_ID}, + {Value : genre_ID} + ]}, + FieldGroup #Descr : {Data : [{Value : descr}]}, + DataPoint #stock : { + Value : stock, + Title : '{i18n>Stock}' + }, + DataPoint #price : { + Value : price, + Title : '{i18n>Price}' + }, + DataPoint #rating : { + Value : rating, + Title : '{i18n>Rating}', + Visualization : #Rating, + MinimumValue : 0, + MaximumValue : 5, + TargetValue : 5 + } +}) { + @Measures.ISOCurrency : currency_code + price +}; + +annotate CatalogService.Books.texts with @(UI : {LineItem : [ + {Value : locale}, + {Value : title}, + {Value : descr} +]}); + +annotate CatalogService.Reviews with @(UI : { + PresentationVariant : { + $Type : 'UI.PresentationVariantType', + SortOrder : [{ + $Type : 'Common.SortOrderType', + Property : modifiedAt, + Descending : true + }, ], + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAnnotation', + Label : '{i18n>Rating}', + Target : '@UI.DataPoint#rating' + }, + { + $Type : 'UI.DataFieldForAnnotation', + Label : '{i18n>User}', + Target : '@UI.FieldGroup#ReviewerAndDate' + }, + { + Value : title, + Label : '{i18n>Title}' + }, + { + Value : text, + Label : '{i18n>Text}' + }, + ], + DataPoint #rating : { + Value : rating, + Visualization : #Rating, + MinimumValue : 0, + MaximumValue : 5 + }, + FieldGroup #ReviewerAndDate : {Data : [ + {Value : createdBy}, + {Value : modifiedAt} + ]} +}); + +annotate CatalogService.Books actions { + @( + Common.SideEffects : { + TargetProperties : ['_it/rating'], + TargetEntities : [ + _it, + _it.reviews + ] + }, + cds.odata.bindingparameter.name : '_it', + Core.OperationAvailable : _it.isReviewable + ) + addReview(rating @title : '{i18n>Rating}', title @title : '{i18n>Title}', text @title : '{i18n>Text}') +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/package.json b/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/package.json new file mode 100644 index 000000000..81d3bd886 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/package.json @@ -0,0 +1,12 @@ +{ + "name": "browse", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/webapp/Component.js b/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/webapp/Component.js new file mode 100644 index 000000000..153759efb --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/webapp/Component.js @@ -0,0 +1,3 @@ +sap.ui.define(["sap/fe/core/AppComponent"], ac => ac.extend("bookshop.Component", { + metadata:{ manifest:'json' } +})) diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/webapp/i18n/i18n.properties b/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/webapp/i18n/i18n.properties new file mode 100644 index 000000000..fbeb70f50 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/webapp/i18n/i18n.properties @@ -0,0 +1,2 @@ +appTitle=Browse Books +appDescription=Browse Books - Sample Application diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/webapp/i18n/i18n_de.properties b/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/webapp/i18n/i18n_de.properties new file mode 100644 index 000000000..2d2581255 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/webapp/i18n/i18n_de.properties @@ -0,0 +1,2 @@ +appTitle=Zeige B\u00FCcher +appDescription=Zeige B\u00FCcher - Beispielanwendung diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/webapp/index.html b/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/webapp/index.html new file mode 100644 index 000000000..99f40f32b --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/webapp/index.html @@ -0,0 +1,35 @@ + + + + + + + Browse Books + + + + +
+ + diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/webapp/manifest.json b/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/webapp/manifest.json new file mode 100644 index 000000000..ec7a8840f --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/browse/webapp/manifest.json @@ -0,0 +1,142 @@ +{ + "_version": "1.8.0", + "sap.app": { + "id": "bookshop", + "type": "application", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + }, + "dataSources": { + "CatalogService": { + "uri": "/api/browse/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + }, + "-sourceTemplate": { + "id": "ui5template.basicSAPUI5ApplicationProject", + "-id": "ui5template.smartTemplate", + "-version": "1.40.12" + }, + "crossNavigation": { + "inbounds": { + "Books-show": { + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "semanticObject": "Books", + "action": "show" + } + } + } + }, + "sap.ui5": { + "dependencies": { + "libs": { + "sap.fe.templates": {} + } + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "i18n/i18n.properties" + }, + "": { + "dataSource": "CatalogService", + "settings": { + "synchronizationMode": "None", + "operationMode": "Server", + "autoExpandSelect" : true, + "earlyRequests": true, + "groupProperties": { + "default": { + "submit": "Auto" + } + } + } + } + }, + "routing": { + "routes": [ + { + "pattern": ":?query:", + "name": "BooksList", + "target": "BooksList" + }, + { + "pattern": "Books({key}):?query:", + "name": "BooksDetails", + "target": "BooksDetails" + }, + { + "pattern": "Books({key}/author({key2}):?query:", + "name": "AuthorsDetails", + "target": "AuthorsDetails" + } + ], + "targets": { + "BooksList": { + "type": "Component", + "id": "BooksList", + "name": "sap.fe.templates.ListReport", + "options": { + "settings" : { + "entitySet" : "Books", + "navigation" : { + "Books" : { + "detail" : { + "route" : "BooksDetails" + } + } + } + } + } + }, + "BooksDetails": { + "type": "Component", + "id": "BooksDetailsList", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet" : "Books", + "navigation" : { + "Authors" : { + "detail" : { + "route" : "AuthorsDetails" + } + } + } + } + } + }, + "AuthorsDetails": { + "type": "Component", + "id": "AuthorsDetailsList", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet" : "Authors" + } + } + } + } + }, + "contentDensities": { + "compact": true, + "cozy": true + } + }, + "sap.ui": { + "technology": "UI5", + "fullWidth": false + }, + "sap.fiori": { + "registrationIds": [], + "archeType": "transactional" + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/common.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/app/common.cds new file mode 100644 index 000000000..c5f121214 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/common.cds @@ -0,0 +1,1193 @@ +/* + Common Annotations shared by all apps +*/ +using {my.bookshop as my} from '../db/index'; +using {sap.common as common} from '@sap/cds/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 : ' ' + }, + { + $Type : 'UI.DataFieldForAction', + Label : '{i18n>AddToOrder}', + Action : 'AdminService.addToOrder' + }, + ] + } +) { + author + @ValueList.entity : 'Authors'; +}; + + +//////////////////////////////////////////////////////////////////////////// +// +// Books Details +// +annotate my.Books with +@(UI : {HeaderInfo : { + TypeName : '{i18n>Book}', + TypeNamePlural : '{i18n>Books}', + TypeImageUrl : 'sap-icon://course-book', + Title : {Value : title}, + Description : {Value : author.name} +}, }); + +//////////////////////////////////////////////////////////////////////////// +// +// Attachments Details +// + +annotate my.Books.attachments with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Attachment}', + TypeNamePlural: '{i18n>Attachments}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Attachments', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink', + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + type @(title: '{i18n>Type}'); + linkUrl @UI.Hidden; + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} +annotate Attachments with @Common: {SideEffects #ContentChanged: { + SourceProperties: [content], + TargetProperties: ['status'], + TargetEntities : [Books.attachments] +}}{}; + +annotate my.Books.references with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Attachment}', + TypeNamePlural: '{i18n>Attachments}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Attachments', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink', + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} { + note @(title: '{i18n>Note}'); + type @(title: '{i18n>Type}'); + linkUrl @UI.Hidden; + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Books.footnotes with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Attachment}', + TypeNamePlural: '{i18n>Attachments}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Attachments', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink', + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} { + note @(title: '{i18n>Note}'); + type @(title: '{i18n>Type}'); + linkUrl @UI.Hidden; + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Chapters.attachments with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Attachment}', + TypeNamePlural: '{i18n>Attachments}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Attachments', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Chapters.references with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Reference}', + TypeNamePlural: '{i18n>References}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy References', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Chapters.footnotes with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Footnote}', + TypeNamePlural: '{i18n>Footnotes}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Footnotes', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Pages.attachments with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Attachment}', + TypeNamePlural: '{i18n>Attachments}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Attachments', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Pages.references with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Reference}', + TypeNamePlural: '{i18n>References}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy References', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Pages.footnotes with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Footnote}', + TypeNamePlural: '{i18n>Footnotes}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Footnotes', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +//////////////////////////////////////////////////////////////////////////// +// +// 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 + @title : '{i18n>Description}' + @UI.MultiLineText; +} + + +//////////////////////////////////////////////////////////////////////////// +// +// Reviews List +// +annotate my.Reviews with +@(UI : { + Identification : [ + { + Value : ID, + ![@UI.Hidden] + }, + {Value : title} + ], + SelectionFields : [ + book_ID, + rating + ], + LineItem : [ + { + Value : modifiedAt, + Label : 'Date' + }, + { + Value : createdBy, + Label : '{i18n>User}' + }, + { + $Type : 'UI.DataFieldForAnnotation', + Label : '{i18n>Book}', + Target : '@UI.FieldGroup#BookAndAuthor' + }, + { + $Type : 'UI.DataFieldForAnnotation', + Label : '{i18n>Rating}', + Target : '@UI.DataPoint#rating' + }, + { + Value : title, + Label : '{i18n>Review}' + } + ], + FieldGroup #BookAndAuthor : {Data : [ + {Value : book.title}, + {Value : book.author.name} + ]}, + DataPoint #rating : { + Value : rating, + Visualization : #Rating, + MinimumValue : 0, + MaximumValue : 5 + } +}); + +annotate my.Reviews with { + ID + @title : '{i18n>ID}' + @UI.HiddenFilter; + title + @title : '{i18n>Title}'; + book + @ValueList.entity : 'Books' + @title : '{i18n>Book}' + @Common : { + Text : book.title, + TextArrangement : #TextOnly + }; + rating + @title : '{i18n>Rating}'; + text + @title : '{i18n>Text}' + @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 : minorUnit} + ]}, +}); + +//////////////////////////////////////////////////////////////////////////// +// +// Fiori requires generated IDs to be annotated with @Core.Computed +// +using {cuid} from '@sap/cds/common'; + +annotate cuid with { + ID + @Core.Computed +} \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/fiori.html b/app/multi-tenant/central-space/cloud-cap-samples-java/app/fiori.html new file mode 100644 index 000000000..0a55fc123 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/fiori.html @@ -0,0 +1,30 @@ + + + + + + + + Bookshop + + + + + + + + + + diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/index.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/app/index.cds new file mode 100644 index 000000000..dcbf40e55 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/index.cds @@ -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 './reviews/fiori-service'; +using from './notes/fiori-service'; +using from './addresses/fiori-service'; +using from './common'; diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/fiori-service.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/fiori-service.cds new file mode 100644 index 000000000..102095b1a --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/fiori-service.cds @@ -0,0 +1,133 @@ +using NotesService from '../../srv/notes-mashup'; + +annotate NotesService.Notes with @odata.draft.enabled @(UI : { + LineItem : [ + { + Value : address.businessPartner, + Label : '{i18n>BusinessPartner}' + }, + { + Value : address.street, + Label : '{i18n>StreetName}' + }, + { + Value : address.city, + Label : '{i18n>CityName}' + }, + { + Value : note, + Label : '{i18n>Note}' + } + ], + HeaderInfo : { + TypeName : '{i18n>Note}', + TypeNamePlural : '{i18n>Notes}', + Title : {Value : '{i18n>Note}'}, + Description : {Value : ID}, + }, + PresentationVariant : { + Text : 'Default', + Visualizations : ['@UI.LineItem'] + }, + Facets : [ + { + $Type : 'UI.ReferenceFacet', + Target : '@UI.FieldGroup#Note', + Label : '{i18n>Note}', + }, + { + $Type : 'UI.ReferenceFacet', + Target : '@UI.FieldGroup#Address', + Label : '{i18n>ShippingAddress}', + } + ], + FieldGroup #Note : {Data : [ + { + Value : note, + Label : '{i18n>Note}' + } + ]}, + FieldGroup #Address : {Data : [ + { + Value : address_businessPartner, + Label : '{i18n>BusinessPartner}' + }, + { + Value : address.ID, + Label : '{i18n>ID}' + }, + { + Value : address.street, + Label : '{i18n>StreetName}' + }, + { + Value : address.houseNumber, + Label : '{i18n>HouseNumber}' + }, + { + Value : address.postalCode, + Label : '{i18n>PostalCode}' + }, + { + Value : address.city, + Label : '{i18n>CityName}' + }, + { + Value : address.country, + Label : '{i18n>Country}' + } + ]}, +}, Common : { + SideEffects #AddressChanges : { + SourceProperties : [address_businessPartner], + TargetEntities : [address] + } +}) { + ID + @title : '{i18n>ID}' + @UI.HiddenFilter; + note + @title : '{i18n>Note}' + @UI.MultiLineText; + address + @(Common : { + FieldControl : #Mandatory, + ValueList : { + CollectionPath : 'Addresses', + Label : '{i18n>ShippingAddress}', + SearchSupported : false, + Parameters : [ + { + $Type : 'Common.ValueListParameterOut', + LocalDataProperty : 'address_businessPartner', + ValueListProperty : 'businessPartner' + }, + { + $Type : 'Common.ValueListParameterOut', + LocalDataProperty : 'address_ID', + ValueListProperty : 'ID', + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'postalCode' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'city' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'country' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'street' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'houseNumber' + }, + ] + } + }); +}; diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/package.json b/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/package.json new file mode 100644 index 000000000..555c053ee --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/package.json @@ -0,0 +1,12 @@ +{ + "name": "notes", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/webapp/Component.js b/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/webapp/Component.js new file mode 100644 index 000000000..aa5843fc8 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/webapp/Component.js @@ -0,0 +1,3 @@ +sap.ui.define(["sap/fe/core/AppComponent"], ac => ac.extend("notes.Component", { + metadata:{ manifest:'json' } +})) diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/webapp/i18n/i18n.properties b/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/webapp/i18n/i18n.properties new file mode 100644 index 000000000..e4d3ed2f6 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/webapp/i18n/i18n.properties @@ -0,0 +1,2 @@ +appTitle=Manage Notes +appDescription=Manage Notes - Sample Application diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/webapp/i18n/i18n_de.properties b/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/webapp/i18n/i18n_de.properties new file mode 100644 index 000000000..5451c4e24 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/webapp/i18n/i18n_de.properties @@ -0,0 +1,2 @@ +appTitle=Administriere Notizen +appDescription=Administriere Notizen - Beispielanwendung diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/webapp/index.html b/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/webapp/index.html new file mode 100644 index 000000000..d91b7503e --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/webapp/index.html @@ -0,0 +1,35 @@ + + + + + + + Manage Notes + + + + +
+ + diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/webapp/manifest.json b/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/webapp/manifest.json new file mode 100644 index 000000000..f75a99b20 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/notes/webapp/manifest.json @@ -0,0 +1,120 @@ +{ + "_version": "1.8.0", + "sap.app": { + "id": "notes", + "type": "application", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + }, + "dataSources": { + "NotesService": { + "uri": "/api/notes/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + }, + "-sourceTemplate": { + "id": "ui5template.basicSAPUI5ApplicationProject", + "-id": "ui5template.smartTemplate", + "-version": "1.40.12" + }, + "crossNavigation": { + "inbounds": { + "Notes-manage": { + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "semanticObject": "Notes", + "action": "manage" + } + } + } + }, + "sap.ui5": { + "dependencies": { + "libs": { + "sap.fe.templates": {} + } + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "i18n/i18n.properties" + }, + "": { + "dataSource": "NotesService", + "settings": { + "synchronizationMode": "None", + "operationMode": "Server", + "autoExpandSelect" : true, + "earlyRequests": true, + "groupProperties": { + "default": { + "submit": "Auto" + } + } + } + } + }, + "routing": { + "routes": [ + { + "pattern": ":?query:", + "name": "NotesList", + "target": "NotesList" + }, + { + "pattern": "Notes({key}):?query:", + "name": "NotesDetails", + "target": "NotesDetails" + } + ], + "targets": { + "NotesList": { + "type": "Component", + "id": "NotesList", + "name": "sap.fe.templates.ListReport", + "options": { + "settings" : { + "entitySet" : "Notes", + "navigation" : { + "Notes" : { + "detail" : { + "route" : "NotesDetails" + } + } + } + } + } + }, + "NotesDetails": { + "type": "Component", + "id": "NotesDetails", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet" : "Notes" + } + } + } + } + }, + "contentDensities": { + "compact": true, + "cozy": true + } + }, + "sap.ui": { + "technology": "UI5", + "fullWidth": false + }, + "sap.fiori": { + "registrationIds": [], + "archeType": "transactional" + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/fiori-service.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/fiori-service.cds new file mode 100644 index 000000000..58a4bbde6 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/fiori-service.cds @@ -0,0 +1,293 @@ +/* + Annotations for the Manage Orders App +*/ + +using AdminService from '../../srv/admin-service'; + + +//////////////////////////////////////////////////////////////////////////// +// +// Common +// +annotate AdminService.OrderItems with { + book @( + Common : { + Text : book.title, + FieldControl : #Mandatory + }, + ValueList.entity : 'Books', + ); + quantity @(Common.FieldControl : #Mandatory); +} + +annotate AdminService.Orders with { + shippingAddress @(Common : { + FieldControl : #Mandatory, + ValueList : { + CollectionPath : 'Addresses', + Label : 'Addresses', + SearchSupported : 'true', + Parameters : [ + { + $Type : 'Common.ValueListParameterOut', + LocalDataProperty : 'shippingAddress_ID', + ValueListProperty : 'ID' + }, + { + $Type : 'Common.ValueListParameterOut', + LocalDataProperty : 'shippingAddress_businessPartner', + ValueListProperty : 'businessPartner' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'postalCode' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'city' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'country' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'street' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'houseNumber' + }, + ] + } + }); +} + +//////////////////////////////////////////////////////////////////////////// +// +// UI +// +annotate AdminService.Orders with @( + title : '{i18n>Order}', + UI : { + //////////////////////////////////////////////////////////////////////////// + // + // Lists of Orders + // + SelectionFields : [ + createdAt, + createdBy + ], + LineItem : [ + { + Value : createdBy, + Label : '{i18n>Customer}' + }, + { + Value : total, + Label : '{i18n>Total}' + }, + { + Value : createdAt, + Label : '{i18n>Date}' + } + ], + //////////////////////////////////////////////////////////////////////////// + // + // Order Details + // + HeaderInfo : { + TypeName : '{i18n>Order}', + TypeNamePlural : '{i18n>Orders}', + Title : { + Label : '{i18n>OrderNumber}', //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 : '{i18n>Customer}' + }, + { + Value : createdAt, + Label : '{i18n>Date}' + }, + {Value : OrderNo}, + { + Value : 'shippingAddress', + Label : '{i18n>ID}' + } + ], + 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>ShippingAddress}', + Target : '@UI.FieldGroup#ShippingAddress' + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>Details}', + Target : '@UI.FieldGroup#Details' + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>OrderItems}', + Target : 'Items/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'ChangeHistoryFacet', + Label : '{i18n>ChangeHistory}', + Target : 'changes/@UI.PresentationVariant', + ![@UI.PartOfPreview]: false + } + ], + FieldGroup #Details : {Data : [ + { + Value : total, + Label : '{i18n>Total}' + }, + { + Value : currency_code, + Label : '{i18n>Currency}' + } + ]}, + FieldGroup #Created : {Data : [ + {Value : createdBy}, + {Value : createdAt}, + ]}, + FieldGroup #Modified : {Data : [ + {Value : modifiedBy}, + {Value : modifiedAt}, + ]}, + FieldGroup #ShippingAddress : {Data : [ + { + Value : shippingAddress_ID, + Label : '{i18n>ShippingAddress}' + }, + { + Value : shippingAddress.houseNumber, + Label : '{i18n>HouseNumber}' + }, + { + Value : shippingAddress.street, + Label : '{i18n>StreetName}' + }, + { + Value : shippingAddress.city, + Label : '{i18n>CityName}' + }, + { + Value : shippingAddress.postalCode, + Label : '{i18n>PostalCode}' + }, + ]} + }, + Common : { + SideEffects #ItemsChanges : { + SourceEntities : [Items], + TargetProperties : ['total'] + }, + SideEffects #CurrencyChanges : { + SourceProperties : [currency_code], + TargetEntities : [currency] + }, + SideEffects #AddressChanges : { + SourceProperties : [shippingAddress_ID], + TargetEntities : [shippingAddress] + } + } +) { + createdAt @UI.HiddenFilter : false; + createdBy @UI.HiddenFilter : false; + total + @Common.FieldControl : #ReadOnly + @Measures.ISOCurrency : currency.code; //Bind the currency field to the amount field +//In all services we always find currency as the code and not as an object that contains a property code +//it seems to work but at least to me this is unconventional modeling. +}; + +//The enity types name is AdminService.my_bookshop_OrderItems +//The annotations below are not generated in edmx WHY? +annotate AdminService.OrderItems with @( + title : '{i18n>OrderItem}', + UI : { + HeaderInfo : { + TypeName : '{i18n>OrderItem}', + TypeNamePlural : '{i18n>OrderItems}', + Title : {Value : book.title}, + Description : {Value : book.descr} + }, + // There is no filterbar for items so the selctionfileds is not needed + SelectionFields : [book_ID], + //////////////////////////////////////////////////////////////////////////// + // + // Lists of OrderItems + // + LineItem : [ + { + Value : book_ID, + Label : '{i18n>Books}' + }, + { + Value : quantity, + }, + { + Value : amount, + } + ], + Identification : [ //Is the main field group + //{Value: ID, Label:'{i18n>ID}'}, //A guid shouldn't be on the UI + { + Value : book_ID, + }, + { + Value : quantity, + }, + { + Value : amount, + } + ], + Facets : [{ + $Type : 'UI.ReferenceFacet', + Label : '{i18n>OrderItem}', + Target : '@UI.Identification' + }, ], + }, + Common : { + SideEffects #AmountChanges : { + SourceProperties : [quantity], + TargetProperties : ['amount'] + }, + SideEffects #BookChanges : { + SourceProperties : [book_ID], + TargetEntities : [book], + TargetProperties : ['amount'] + } + } +) { + @title: '{i18n>Amount}' + amount + @Common.FieldControl : #ReadOnly; + + @title: '{i18n>Quantity}' + quantity; + @title: '{i18n>Book}' + book; +//ERROR ALERT: The following line refering to the parents currency code will lead to a server error +//@Measures.ISOCurrency:parent.currency.code; //Bind the currency field to the quantity field of the parent +}; diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/package.json b/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/package.json new file mode 100644 index 000000000..eecfe0e9f --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/package.json @@ -0,0 +1,12 @@ +{ + "name": "orders", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/webapp/Component.js b/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/webapp/Component.js new file mode 100644 index 000000000..2417b6819 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/webapp/Component.js @@ -0,0 +1,3 @@ +sap.ui.define(["sap/fe/core/AppComponent"], ac => ac.extend("orders.Component", { + metadata:{ manifest:'json' } +})) diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/webapp/i18n/i18n.properties b/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/webapp/i18n/i18n.properties new file mode 100644 index 000000000..441b619d8 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/webapp/i18n/i18n.properties @@ -0,0 +1,2 @@ +appTitle=Manage Orders +appDescription=Manage Orders - Sample Application diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/webapp/i18n/i18n_de.properties b/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/webapp/i18n/i18n_de.properties new file mode 100644 index 000000000..df5222671 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/webapp/i18n/i18n_de.properties @@ -0,0 +1,2 @@ +appTitle=Administriere Bestellungen +appDescription=Administriere Bestellungen - Beispielanwendung diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/webapp/index.html b/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/webapp/index.html new file mode 100644 index 000000000..1b3b73558 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/webapp/index.html @@ -0,0 +1,35 @@ + + + + + + + Manage Orders + + + + +
+ + \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/webapp/manifest.json b/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/webapp/manifest.json new file mode 100644 index 000000000..758e31f2a --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/orders/webapp/manifest.json @@ -0,0 +1,184 @@ +{ + "_version": "1.8.0", + "sap.app": { + "id": "orders", + "type": "application", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + }, + "dataSources": { + "AdminService": { + "uri": "/api/admin/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + }, + "-sourceTemplate": { + "id": "ui5template.basicSAPUI5ApplicationProject", + "-id": "ui5template.smartTemplate", + "-version": "1.40.12" + }, + "crossNavigation": { + "inbounds": { + "Orders-manage": { + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "semanticObject": "Orders", + "action": "manage" + } + } + } + }, + "sap.ui5": { + "dependencies": { + "libs": { + "sap.fe.templates": {} + } + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "i18n/i18n.properties" + }, + "": { + "dataSource": "AdminService", + "settings": { + "synchronizationMode": "None", + "operationMode": "Server", + "autoExpandSelect" : true, + "earlyRequests": true, + "groupProperties": { + "default": { + "submit": "Auto" + } + } + } + } + }, + "routing": { + "routes": [ + { + "pattern": ":?query:", + "name": "OrdersList", + "target": "OrdersList" + }, + { + "pattern": "Orders({key}):?query:", + "name": "OrdersDetails", + "target": "OrdersDetails" + }, + { + "pattern": "Orders({boo})/Items({boo2}):?query:", + "name": "OrderItemsDetails", + "target": "OrderItemsDetails" + }, + { + "pattern": "Books({key}):?query:", + "name": "BooksDetails", + "target": "BooksDetails" + } + ], + "targets": { + "OrdersList": { + "type": "Component", + "id": "OrdersList", + "name": "sap.fe.templates.ListReport", + "options": { + "settings" : { + "entitySet" : "Orders", + "navigation" : { + "Orders" : { + "detail" : { + "route" : "OrdersDetails" + } + } + } + } + } + }, + "OrdersDetails": { + "type": "Component", + "id": "OrdersDetails", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet": "Orders", + "navigation" : { + "Items": { + "detail": { + "route": "OrderItemsDetails" + } + }, + "book": { + "detail": { + "route": "BooksDetails" + } + }, + "dummy": { + "detail": { + "route": "BooksDetails" + } + } + } + } + } + }, + "OrderItemsDetails": { + "type": "Component", + "id": "OrderItemsDetails", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet": "OrderItems" + } + } + }, + "BooksDetails": { + "type": "Component", + "id": "BooksDetails", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet": "Books", + "navigation": { + "author": { + "detail": { + "route": "AuthorsDetails" + } + } + } + } + } + }, + "AuthorsDetails": { + "type": "Component", + "id": "AuthorsDetails", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet": "Authors" + } + } + } + } + }, + "contentDensities": { + "compact": true, + "cozy": true + } + }, + "sap.ui": { + "technology": "UI5", + "fullWidth": false + }, + "sap.fiori": { + "registrationIds": [], + "archeType": "transactional" + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/package-lock.json b/app/multi-tenant/central-space/cloud-cap-samples-java/app/package-lock.json new file mode 100644 index 000000000..cc337716f --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/package-lock.json @@ -0,0 +1,2014 @@ +{ + "name": "approuter", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "approuter", + "dependencies": { + "@sap/approuter": "^13" + } + }, + "node_modules/@sap/approuter": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@sap/approuter/-/approuter-13.1.1.tgz", + "integrity": "sha512-IinOHss1M59eEW4b8lCjSKsi4upaesh82tiH/TOFmSgbREawKct7IF743oN953S0JY8y5w5dcfTGToU8lfjTYA==", + "dependencies": { + "@sap/audit-logging": "5.6.3", + "@sap/e2e-trace": "^3.0.0", + "@sap/logging": "^6.1.1", + "@sap/xsenv": "^3.4.0", + "@sap/xssec": "^3.2.17", + "agentkeepalive": "2.0.5", + "axios": "0.27.2", + "axios-cookiejar-support": "2.0.3", + "base64-url": "2.3.3", + "basic-auth": "1.0.3", + "body-parser": "1.20.0", + "cf-nodejs-logging-support": "^6.14.0", + "commander": "2.9.0", + "compressible": "2.0.18", + "compression": "1.7.4", + "connect": "3.6.5", + "cookie": "0.2.2", + "cookie-parser": "1.3.5", + "cookie-signature": "1.1.0", + "debug": "4.3.2", + "deepmerge": "2.1.1", + "encodeurl": "1.0.2", + "express-session": "1.17.0", + "http-proxy-agent": "4.0.1", + "https-proxy-agent": "5.0.0", + "ioredis": "4.28.5", + "jwt-decode": "2.0.1", + "lodash": "4.17.21", + "lru-cache": "4.0.0", + "mime": "1.4.1", + "ms": "2.1.1", + "mustache": "2.2.1", + "node-cache": "4.1.1", + "node-forge": "^1.3.0", + "passport": "^0.6.0", + "query-string": "7.1.2", + "request-stats": "2.0.1", + "safe-regex": "1.1.0", + "scmp": "1.0.0", + "send": "0.16.2", + "serve-static": "1.13.2", + "tough-cookie": "4.0.0", + "tv4": "1.2.7", + "uid-safe": "2.1.5", + "urijs": "^1.19.11", + "uuid": "8.3.2", + "validator": "13.7.0", + "verror": "1.10.0", + "ws": "7.4.6" + }, + "engines": { + "node": "^14.0.0 || ^16.0.0" + } + }, + "node_modules/@sap/audit-logging": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/@sap/audit-logging/-/audit-logging-5.6.3.tgz", + "integrity": "sha512-Uden+nsIxfbnsVrW9Jm3spZ8sNgCOdmZMbBQ24CeElW7qv82rH3Rpm2b+9qRgahWGxQlwws5LPZc0zESMw/mdA==", + "hasShrinkwrap": true, + "dependencies": { + "@sap/xssec": "^3.2.15", + "debug": "4.3.3", + "fetch-retry": "4.1.0", + "node-cache": "5.1.0", + "node-fetch": "2.6.7" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || ^14.0.0 || ^16.0.0 || ^18.0.0" + } + }, + "node_modules/@sap/audit-logging/node_modules/@sap/xssec": { + "version": "3.2.15", + "dependencies": { + "axios": "^0.26.0", + "debug": "^4.3.2", + "jsonwebtoken": "^9.0.0", + "lru-cache": "^6.0.0", + "node-rsa": "^1.1.1", + "valid-url": "1.0.9" + } + }, + "node_modules/@sap/audit-logging/node_modules/asn1": { + "version": "0.2.6", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/@sap/audit-logging/node_modules/axios": { + "version": "0.26.1", + "dependencies": { + "follow-redirects": "^1.14.8" + } + }, + "node_modules/@sap/audit-logging/node_modules/buffer-equal-constant-time": { + "version": "1.0.1" + }, + "node_modules/@sap/audit-logging/node_modules/clone": { + "version": "2.1.2" + }, + "node_modules/@sap/audit-logging/node_modules/debug": { + "version": "4.3.3", + "dependencies": { + "ms": "2.1.2" + } + }, + "node_modules/@sap/audit-logging/node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@sap/audit-logging/node_modules/fetch-retry": { + "version": "4.1.0" + }, + "node_modules/@sap/audit-logging/node_modules/follow-redirects": { + "version": "1.15.2" + }, + "node_modules/@sap/audit-logging/node_modules/jsonwebtoken": { + "version": "9.0.0", + "dependencies": { + "jws": "^3.2.2", + "lodash": "^4.17.21", + "ms": "^2.1.1", + "semver": "^7.3.8" + } + }, + "node_modules/@sap/audit-logging/node_modules/jwa": { + "version": "1.4.1", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@sap/audit-logging/node_modules/jws": { + "version": "3.2.2", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@sap/audit-logging/node_modules/lodash": { + "version": "4.17.21" + }, + "node_modules/@sap/audit-logging/node_modules/lru-cache": { + "version": "6.0.0", + "dependencies": { + "yallist": "^4.0.0" + } + }, + "node_modules/@sap/audit-logging/node_modules/ms": { + "version": "2.1.2" + }, + "node_modules/@sap/audit-logging/node_modules/node-cache": { + "version": "5.1.0", + "dependencies": { + "clone": "2.x" + } + }, + "node_modules/@sap/audit-logging/node_modules/node-fetch": { + "version": "2.6.7", + "dependencies": { + "whatwg-url": "^5.0.0" + } + }, + "node_modules/@sap/audit-logging/node_modules/node-rsa": { + "version": "1.1.1", + "dependencies": { + "asn1": "^0.2.4" + } + }, + "node_modules/@sap/audit-logging/node_modules/safe-buffer": { + "version": "5.2.1" + }, + "node_modules/@sap/audit-logging/node_modules/safer-buffer": { + "version": "2.1.2" + }, + "node_modules/@sap/audit-logging/node_modules/semver": { + "version": "7.3.8", + "dependencies": { + "lru-cache": "^6.0.0" + } + }, + "node_modules/@sap/audit-logging/node_modules/tr46": { + "version": "0.0.3" + }, + "node_modules/@sap/audit-logging/node_modules/valid-url": { + "version": "1.0.9" + }, + "node_modules/@sap/audit-logging/node_modules/webidl-conversions": { + "version": "3.0.1" + }, + "node_modules/@sap/audit-logging/node_modules/whatwg-url": { + "version": "5.0.0", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/@sap/audit-logging/node_modules/yallist": { + "version": "4.0.0" + }, + "node_modules/@sap/e2e-trace": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@sap/e2e-trace/-/e2e-trace-3.2.0.tgz", + "integrity": "sha512-tNqLk/RhX6oc2ScFCJkVtSGPWqrxRLAUfIsCN1Dn4yGHc+gHQVdmyVTDkgKdgw9m4kU+emD2PjDXpo2VwAb0Pg==", + "hasShrinkwrap": true, + "dependencies": { + "request-stats": "3.0.0" + }, + "engines": { + "node": "^8.0.0 || ^10.0.0 || ^12.0.0 || ^14.0.0 || ^16.0.0 || ^18.0.0" + } + }, + "node_modules/@sap/e2e-trace/node_modules/http-headers": { + "version": "3.0.2", + "dependencies": { + "next-line": "^1.1.0" + } + }, + "node_modules/@sap/e2e-trace/node_modules/next-line": { + "version": "1.1.0" + }, + "node_modules/@sap/e2e-trace/node_modules/once": { + "version": "1.4.0", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/@sap/e2e-trace/node_modules/request-stats": { + "version": "3.0.0", + "dependencies": { + "http-headers": "^3.0.1", + "once": "^1.4.0" + } + }, + "node_modules/@sap/e2e-trace/node_modules/wrappy": { + "version": "1.0.2" + }, + "node_modules/@sap/logging": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@sap/logging/-/logging-6.2.0.tgz", + "integrity": "sha512-2AYADnDN/1u8Fpa9EqTABnLl4GPAwMoOXaWMFJKwrvSTSr6RSQK924uUMQQBClwcwCwktcf4xlrWCFSztBjfxQ==", + "hasShrinkwrap": true, + "dependencies": { + "@sap/e2e-trace": "^3.1.0", + "lodash": "4.17.21", + "moment": "2.29.4" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || ^14.0.0 || ^16.0.0 || ^18.0.0" + } + }, + "node_modules/@sap/logging/node_modules/@sap/e2e-trace": { + "version": "3.2.0", + "dependencies": { + "request-stats": "3.0.0" + } + }, + "node_modules/@sap/logging/node_modules/@sap/e2e-trace/node_modules/http-headers": { + "version": "3.0.2", + "dependencies": { + "next-line": "^1.1.0" + } + }, + "node_modules/@sap/logging/node_modules/@sap/e2e-trace/node_modules/next-line": { + "version": "1.1.0" + }, + "node_modules/@sap/logging/node_modules/@sap/e2e-trace/node_modules/once": { + "version": "1.4.0", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/@sap/logging/node_modules/@sap/e2e-trace/node_modules/request-stats": { + "version": "3.0.0", + "dependencies": { + "http-headers": "^3.0.1", + "once": "^1.4.0" + } + }, + "node_modules/@sap/logging/node_modules/@sap/e2e-trace/node_modules/wrappy": { + "version": "1.0.2" + }, + "node_modules/@sap/logging/node_modules/lodash": { + "version": "4.17.21" + }, + "node_modules/@sap/logging/node_modules/moment": { + "version": "2.29.4" + }, + "node_modules/@sap/xsenv": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@sap/xsenv/-/xsenv-3.4.0.tgz", + "integrity": "sha512-bZ/NFhS+wZI0JlMO1OOBEThfyOTmf2x5oQ+wToJGkZ2T5+gLUE3emZiC4iHA+BuSmUtO+vYoe29Q1qiE4qaiJQ==", + "hasShrinkwrap": true, + "dependencies": { + "debug": "4.3.3", + "node-cache": "^5.1.0", + "verror": "1.10.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || ^14.0.0 || ^16.0.0 || ^18.0.0" + } + }, + "node_modules/@sap/xsenv/node_modules/assert-plus": { + "version": "1.0.0" + }, + "node_modules/@sap/xsenv/node_modules/clone": { + "version": "2.1.2" + }, + "node_modules/@sap/xsenv/node_modules/core-util-is": { + "version": "1.0.2" + }, + "node_modules/@sap/xsenv/node_modules/debug": { + "version": "4.3.3", + "dependencies": { + "ms": "2.1.2" + } + }, + "node_modules/@sap/xsenv/node_modules/extsprintf": { + "version": "1.4.1" + }, + "node_modules/@sap/xsenv/node_modules/ms": { + "version": "2.1.2" + }, + "node_modules/@sap/xsenv/node_modules/node-cache": { + "version": "5.1.2", + "dependencies": { + "clone": "2.x" + } + }, + "node_modules/@sap/xsenv/node_modules/verror": { + "version": "1.10.0", + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/@sap/xssec": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@sap/xssec/-/xssec-3.6.1.tgz", + "integrity": "sha512-OJouwIWClefpsJ8rVCziEydeDHDNOMA4hjsjw9OqolbbObaiYMMDRU0YJbPe7XL5JkLgrtt+CLCBCsNERxcCZg==", + "dependencies": { + "axios": "^1.6", + "debug": "^4.3.4", + "jsonwebtoken": "^9.0.2", + "node-rsa": "^1.1.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@sap/xssec/node_modules/axios": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/@sap/xssec/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@sap/xssec/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-2.0.5.tgz", + "integrity": "sha512-dlXxjfkCrcEPmvJju6ypP6/eq1q0l+cu0u10IhKfiwMoy4yH73n0TQ2jMO2H39xbcC3Q4cWUFPkNk1b3GLEklg==", + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "dependencies": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "node_modules/axios-cookiejar-support": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/axios-cookiejar-support/-/axios-cookiejar-support-2.0.3.tgz", + "integrity": "sha512-tvMB+0JhxXLjjvePsXzqXhBI4DMlW4ImR4pKKNl+xclwF0IviNV+CkuhubQCCFjPzOXv7PIzOq3z7WFiF9pMpw==", + "dependencies": { + "http-cookie-agent": "^1.0.2" + }, + "engines": { + "node": ">=12.19.0 <13.0.0 || >=14.5.0" + }, + "peerDependencies": { + "axios": ">=0.20.0", + "tough-cookie": ">=4.0.0" + } + }, + "node_modules/base64-url": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/base64-url/-/base64-url-2.3.3.tgz", + "integrity": "sha512-dLMhIsK7OplcDauDH/tZLvK7JmUZK3A7KiQpjNzsBrM6Etw7hzNI1tLEywqJk9NnwkgWuFKSlx/IUO7vF6Mo8Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/basic-auth": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.0.3.tgz", + "integrity": "sha512-fkXSqXkCTgBy5HVNQ2wP1Fnc/JZjnREwM3hfU8h5RyUN8X9WMQBJem6ZmlsSs7Y4f3fQ7z09vcARgOa0iaPaZA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/body-parser": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/cf-nodejs-logging-support": { + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/cf-nodejs-logging-support/-/cf-nodejs-logging-support-6.14.1.tgz", + "integrity": "sha512-ORQL/J0qe2isOPwlXKafaCGmNkQLngb/6KgxLJQ+pfxynAfVUn6tJMtEwH7U0izBSzEtFsYGXa6H4DmIH/8Hrg==", + "dependencies": { + "json-stringify-safe": "^5.0.1", + "jsonwebtoken": "^9.0.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha512-bmkUukX8wAOjHdN26xj5c4ctEV22TQ7dQYhSmuckKhToXrkUn0iIaolHdIxYYqD55nhpSPA9zPQ1yP57GdXP2A==", + "dependencies": { + "graceful-readlink": ">= 1.0.0" + }, + "engines": { + "node": ">= 0.6.x" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/connect": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.5.tgz", + "integrity": "sha512-B+WTJ0bDgjQugnbNF7fWGvwEgTj9Isdk3Y7yTZlgCuVe+hpl/do8frEMeimx7sRMPW3oZA+EsC9uDZL8MaaAwQ==", + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.0.6", + "parseurl": "~1.3.2", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.2.2.tgz", + "integrity": "sha512-QT1/SH6oF6jrC9K4rlWpa/5FgqUZuh/Ohl4NvGAgSm67DsieBdTz/XsiVQwBKEJMnw7Tui5uBuC7k1yUAmPO2g==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-parser": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.3.5.tgz", + "integrity": "sha512-YN/8nzPcK5o6Op4MIzAd4H4qUal5+3UaMhVIeaafFYL0pKvBQA/9Yhzo7ZwvBpjdGshsiTAb1+FC37M6RdPDFg==", + "dependencies": { + "cookie": "0.1.3", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-parser/node_modules/cookie": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz", + "integrity": "sha512-mWkFhcL+HVG1KjeCjEBVJJ7s4sAGMLiBDFSDs4bzzvgLZt7rW8BhP6XV/8b1+pNvx/skd3yYxPuaF3Z6LlQzyw==", + "engines": { + "node": "*" + } + }, + "node_modules/cookie-parser/node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/cookie-signature": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.1.0.tgz", + "integrity": "sha512-Alvs19Vgq07eunykd3Xy2jF0/qSNv2u7KDbAek9H5liV1UMijbqFs5cycZvv5dVsvseT/U4H8/7/w8Koh35C4A==", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + }, + "node_modules/debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/deepmerge": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.1.1.tgz", + "integrity": "sha512-urQxA1smbLZ2cBbXbaYObM1dJ82aJ2H57A1C/Kklfh/ZN1bgH4G/n5KWhdNfOK11W98gqZfyYj7W4frJJRwA2w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/denque": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express-session": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.0.tgz", + "integrity": "sha512-t4oX2z7uoSqATbMfsxWMbNjAL0T5zpvcJCk3Z9wnPPN7ibddhnmDZXHfEcoBMG2ojKXZoCyPMc5FbtK+G7SoDg==", + "dependencies": { + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.3", + "safe-buffer": "5.2.0", + "uid-safe": "~2.1.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/express-session/node_modules/cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express-session/node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/express-session/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express-session/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/express-session/node_modules/safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + }, + "node_modules/extsprintf": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", + "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/filter-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", + "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.6.tgz", + "integrity": "sha512-immlyyYCPWG2tajlYBhZ6cjLAv1QAclU8tKS0d27ZtPqm/+iddy16GT3xLExg+V4lIETLpPwaYQAlZHNE//dPA==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.3.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w==" + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-cookie-agent": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/http-cookie-agent/-/http-cookie-agent-1.0.6.tgz", + "integrity": "sha512-Ei0BDjMfy6MSXATmCZ5nWr935NLYl6eD/BTxVGOIrKAlg4xDtMdk+8a+caq6Qwa4FACn+vACj89pFKlXmHOnkQ==", + "dependencies": { + "agent-base": "^6.0.2" + }, + "engines": { + "node": ">=12.19.0 <13.0.0 || >=14.5.0" + }, + "peerDependencies": { + "tough-cookie": "^4.0.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-headers": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-headers/-/http-headers-3.0.2.tgz", + "integrity": "sha512-87E1I+2Wg4dxxz4rcxElo3dxO/w1ZtgL1yA0Sb6vH3qU16vRKq1NjWQv9SCY3ly2OQROcoxHZOUpmelS+k6wOw==", + "dependencies": { + "next-line": "^1.1.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ioredis": { + "version": "4.28.5", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.28.5.tgz", + "integrity": "sha512-3GYo0GJtLqgNXj4YhrisLaNNvWSNwSS2wS4OELGfGxH8I69+XfNdnmV1AyN+ZqMh0i7eX+SWjrwFKDBDgfBC1A==", + "dependencies": { + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.1", + "denque": "^1.1.0", + "lodash.defaults": "^4.2.0", + "lodash.flatten": "^4.4.0", + "lodash.isarguments": "^3.1.0", + "p-map": "^2.1.0", + "redis-commands": "1.7.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jwt-decode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.0.1.tgz", + "integrity": "sha512-/KEXk2wGfWoSM2SHQk8mq9n/Rd6ahB0XIZt0jEcNy4tQXeDHU4oNOGK1shSVstIQm97qowy6dFgUAHB3zbOD8g==" + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, + "node_modules/lru-cache": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.0.tgz", + "integrity": "sha512-WKhDkjlLwzE8jAQdQlsxLUQTPXLCKX/4cJk6s5AlRtJkDBk0IKH5O51bVDH61K9N4bhbbyvLM6EiOuE8ovApPA==", + "dependencies": { + "pseudomap": "^1.0.1", + "yallist": "^2.0.0" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "bin": { + "mime": "cli.js" + } + }, + "node_modules/mime-db": { + "version": "1.53.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.53.0.tgz", + "integrity": "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "node_modules/mustache": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-2.2.1.tgz", + "integrity": "sha512-azYRexmi9y6h2lk2JqfBLh1htlDMjKYyEYOkxoGKa0FRdr5aY4f5q8bH4JIecM181DtUEYLSz8PcRO46mgzMNQ==", + "bin": { + "mustache": "bin/mustache" + }, + "engines": { + "npm": ">=1.4.0" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/next-line": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-line/-/next-line-1.1.0.tgz", + "integrity": "sha512-+I10J3wKNoKddNxn0CNpoZ3eTZuqxjNM3b1GImVx22+ePI+Y15P8g/j3WsbP0fhzzrFzrtjOAoq5NCCucswXOQ==" + }, + "node_modules/node-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-4.1.1.tgz", + "integrity": "sha512-1IdglJ3+6RO7j2jGVSbWG7CD/H7axG770BbuopZNDqKpQu1ol89xC4Qc+hd6uBEewjsoCZ6xRIY8BRa5PkHgTQ==", + "dependencies": { + "clone": "2.x", + "lodash": "4.x" + }, + "engines": { + "node": ">= 0.4.6" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-rsa": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/node-rsa/-/node-rsa-1.1.1.tgz", + "integrity": "sha512-Jd4cvbJMryN21r5HgxQOpMEqv+ooke/korixNNK3mGqfGJmy0M77WDDzo/05969+OkMy3XW1UuZsSmW9KQm7Fw==", + "dependencies": { + "asn1": "^0.2.4" + } + }, + "node_modules/object-inspect": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/passport": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.6.0.tgz", + "integrity": "sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" + }, + "node_modules/psl": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.13.0.tgz", + "integrity": "sha512-BFwmFXiJoFqlUpZ5Qssolv15DMyc84gTBds1BjsV1BfXEo1UyyD7GsmN67n7J77uRhoSNW1AXtXKPLcBFQn9Aw==", + "dependencies": { + "punycode": "^2.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/query-string": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.2.tgz", + "integrity": "sha512-KPbFzz/8pmtYOMH6zlYZgqTYJKQ18FxwfW3RLHIBwHWQ0iQG18X16XtIOk68ddfaM6j3grjYSnMPMrqQEjwR4w==", + "dependencies": { + "decode-uri-component": "^0.2.1", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/redis-commands": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz", + "integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==" + }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/request-stats": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/request-stats/-/request-stats-2.0.1.tgz", + "integrity": "sha512-GZQvTZqbUx9gXrRfj1c9pMcFzyLeJEpV2P5qXxGwf1I2ZRswRsCNYPsuwnFLNRZQamlsrinzKQnExXBGgFzFCw==", + "dependencies": { + "http-headers": "^3.0.1", + "once": "^1.4.0" + } + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "engines": { + "node": ">=0.12" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/scmp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/scmp/-/scmp-1.0.0.tgz", + "integrity": "sha512-gCzsBFLpXrXnq60hYFV4hc4b5a3nIWTKtFWMYvlcXqs5gHKTR445CO3QbFRZW/O+9tRIVTeC46/MXbq1Se/1Sw==", + "deprecated": "scmp v2 uses improved core crypto comparison since Node v6.6.0" + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/send/node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==" + }, + "node_modules/send/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/send/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/send/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "node_modules/send/node_modules/statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/split-on-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" + }, + "node_modules/statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha512-wuTCPGlJONk/a1kqZ4fQM2+908lC7fa7nPYpTC1EhnvqLX/IICbeP1OZGDtA374trpSq68YubKUMo8oRhN46yg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tv4": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/tv4/-/tv4-1.2.7.tgz", + "integrity": "sha512-7W00xKKK9ccSXbN8E1FUKe+PJKlQc3HcPRM1y9WnplFVucoWFBpTNCGJNMHG04+yf5lQKUKx71yt0mluqnbCzw==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "dependencies": { + "random-bytes": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/urijs": { + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validator": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" + } + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/package.json b/app/multi-tenant/central-space/cloud-cap-samples-java/app/package.json new file mode 100644 index 000000000..fa9d34967 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/package.json @@ -0,0 +1,9 @@ +{ + "name": "approuter", + "dependencies": { + "@sap/approuter": "16.8.2" + }, + "scripts": { + "start": "node node_modules/@sap/approuter/approuter.js" + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/fiori-service.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/fiori-service.cds new file mode 100644 index 000000000..ee77c5c4d --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/fiori-service.cds @@ -0,0 +1,90 @@ +/* + Annotations for the Browse Books App +*/ + +using ReviewService from '../../srv/review-service'; + +annotate ReviewService.Reviews with @(UI : { + HeaderInfo : { + TypeName : '{i18n>Review}', + TypeNamePlural : '{i18n>Reviews}', + Title : {Value : title}, + Description : {Value : createdBy}, + }, + PresentationVariant : { + Text : 'Default', + SortOrder : [{ + Property : modifiedAt, + Descending : true + }], + Visualizations : ['@UI.LineItem'] + }, + SelectionFields : [ + book_ID, + rating + ], + HeaderFacets : [{ + $Type : 'UI.ReferenceFacet', + Target : '@UI.DataPoint#rating' + }, ], + Facets : [ + { + $Type : 'UI.ReferenceFacet', + Target : '@UI.FieldGroup#General', + Label : '{i18n>General}' + }, + { + $Type : 'UI.ReferenceFacet', + Target : '@UI.FieldGroup#Review', + Label : '{i18n>Review}', + } + ], + FieldGroup #General : {Data : [ + { + Value : createdAt, + Label : '{i18n>Created}' + }, + { + Value : createdBy, + Label : '{i18n>CreatedBy}' + }, + { + Value : modifiedAt, + Label : '{i18n>Modified}' + }, + { + Value : modifiedBy, + Label : '{i18n>ModifiedBy}' + }, + {Value : book_ID}, + ]}, + FieldGroup #Review : {Data : [ + { + Value : rating, + Label : '{i18n>Rating}' + }, + { + Value : title, + Label : '{i18n>Title}' + }, + { + Value : text, + Label : '{i18n>Text}' + } + ]}, + FieldGroup #BookAndAuthor : {Data : [ + {Value : book.title}, + {Value : book.author.name} + ]}, + DataPoint #rating : { + Title : '{i18n>Rating}', + Value : rating, + Visualization : #Rating, + MinimumValue : 0, + MaximumValue : 5 + } +}) { + rating @title : '{i18n>Rating}'; + title @title : '{i18n>Title}'; + text @title : '{i18n>Text}' @UI.MultiLineText; +}; diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/package.json b/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/package.json new file mode 100644 index 000000000..22ad679de --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/package.json @@ -0,0 +1,12 @@ +{ + "name": "reviews", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/webapp/Component.js b/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/webapp/Component.js new file mode 100644 index 000000000..4140a28ee --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/webapp/Component.js @@ -0,0 +1,3 @@ +sap.ui.define(["sap/fe/core/AppComponent"], ac => ac.extend("reviews.Component", { + metadata:{ manifest:'json' } +})) diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/webapp/i18n/i18n.properties b/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/webapp/i18n/i18n.properties new file mode 100644 index 000000000..9aadf3e7c --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/webapp/i18n/i18n.properties @@ -0,0 +1,2 @@ +appTitle=Manage Reviews +appDescription=Manage Reviews - Sample Application diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/webapp/i18n/i18n_de.properties b/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/webapp/i18n/i18n_de.properties new file mode 100644 index 000000000..1cc53e4cc --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/webapp/i18n/i18n_de.properties @@ -0,0 +1,2 @@ +appTitle=Administriere Reviews +appDescription=Administriere Reviews - Beispielanwendung diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/webapp/index.html b/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/webapp/index.html new file mode 100644 index 000000000..d22158946 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/webapp/index.html @@ -0,0 +1,35 @@ + + + + + + + Manage Reviews + + + + +
+ + \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/webapp/manifest.json b/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/webapp/manifest.json new file mode 100644 index 000000000..78dd8f8c6 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/reviews/webapp/manifest.json @@ -0,0 +1,142 @@ +{ + "_version": "1.8.0", + "sap.app": { + "id": "reviews", + "type": "application", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + }, + "dataSources": { + "ReviewService": { + "uri": "/api/review/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + }, + "-sourceTemplate": { + "id": "ui5template.basicSAPUI5ApplicationProject", + "-id": "ui5template.smartTemplate", + "-version": "1.40.12" + }, + "crossNavigation": { + "inbounds": { + "Reviews-manage": { + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "semanticObject": "Reviews", + "action": "manage" + } + } + } + }, + "sap.ui5": { + "dependencies": { + "libs": { + "sap.fe.templates": {} + } + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "i18n/i18n.properties" + }, + "": { + "dataSource": "ReviewService", + "settings": { + "synchronizationMode": "None", + "operationMode": "Server", + "autoExpandSelect" : true, + "earlyRequests": true, + "groupProperties": { + "default": { + "submit": "Auto" + } + } + } + } + }, + "routing": { + "routes": [ + { + "pattern": ":?query:", + "name": "ReviewsList", + "target": "ReviewsList" + }, + { + "pattern": "Reviews({key}):?query:", + "name": "ReviewsDetails", + "target": "ReviewsDetails" + }, + { + "pattern": "Reviews({key}/book({key2}):?query:", + "name": "BooksDetails", + "target": "BooksDetails" + } + ], + "targets": { + "ReviewsList": { + "type": "Component", + "id": "ReviewsList", + "name": "sap.fe.templates.ListReport", + "options": { + "settings" : { + "entitySet" : "Reviews", + "navigation" : { + "Reviews" : { + "detail" : { + "route" : "ReviewsDetails" + } + } + } + } + } + }, + "ReviewsDetails": { + "type": "Component", + "id": "ReviewsDetails", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet" : "Reviews", + "navigation" : { + "Books" : { + "detail" : { + "route" : "BooksDetails" + } + } + } + } + } + }, + "BooksDetails": { + "type": "Component", + "id": "BooksDetails", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet" : "Books" + } + } + } + } + }, + "contentDensities": { + "compact": true, + "cozy": true + } + }, + "sap.ui": { + "technology": "UI5", + "fullWidth": false + }, + "sap.fiori": { + "registrationIds": [], + "archeType": "transactional" + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/vue/app.js b/app/multi-tenant/central-space/cloud-cap-samples-java/app/vue/app.js new file mode 100644 index 000000000..8b4a6f052 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/vue/app.js @@ -0,0 +1,122 @@ +/* global Vue axios */ //> from index.html +const $ = (sel) => document.querySelector(sel); + +const httpClient = axios.create({ + withCredentials: true, +}); + +// adding csrf token to request headers +axios + .head("/api/browse", { + headers: { + "X-CSRF-Token": "Fetch", + "X-Requested-With": "XMLHttpRequest", + }, + }) + .then((res) => { + xcsrfToken = res.headers["x-csrf-token"]; + httpClient.defaults.headers.common["X-CSRF-Token"] = xcsrfToken; + }); + +const GET = (url) => httpClient.get("/api/browse" + url); +const POST = (cmd, data) => httpClient.post("/api/browse" + cmd, data); + +const bookshop = new Vue({ + el: "#app", + + data: { + books: [], + reviews: [], + book: undefined, + review: undefined, + order: { quantity: 1, succeeded: "", failed: "" }, + message: {}, + Ratings: Object.entries({ + 5: "★★★★★", + 4: "★★★★", + 3: "★★★", + 2: "★★", + 1: "★", + }).reverse(), + }, + + methods: { + searchBooks: ({ target: { value: v } }) => + bookshop.fetchBooks(v && "&$search=" + v), + + searchReviews: ({ target: { value: v } }) => + bookshop.fetchReviews(v && "?$search=" + v), + + async fetchBooks(etc = "") { + const { data } = await GET(`/Books?$expand=author,genre,currency${etc}`); + bookshop.books = data.value; + }, + + async fetchReviews(etc = "") { + const { data } = await GET( + `/Books(ID=${bookshop.book.ID})/reviews${etc}` + ); + bookshop.reviews = data.value; + }, + + async inspectBook(eve) { + const book = (bookshop.book = + bookshop.books[eve.currentTarget.rowIndex - 1]); + const res = await GET( + `/Books(ID=${book.ID})?$expand=reviews&$select=descr,stock` + ); + Object.assign(book, res.data); + bookshop.order = { quantity: 1 }; + bookshop.reviews = book.reviews; + setTimeout(() => $("form > input").focus(), 111); + }, + + async submitOrder() { + const { book, order } = bookshop, + quantity = parseInt(bookshop.order.quantity) || 1; // REVISIT: Okra should be less strict + try { + const res = await POST(`/submitOrder`, { quantity, book: book.ID }); + book.stock = res.data.stock; + bookshop.order = { + quantity, + succeeded: `Successfully ordered ${quantity} item(s).`, + }; + } catch (e) { + bookshop.order = { quantity, failed: e.response.data.error.message }; + } + }, + + async inspectReview(eve) { + bookshop.review = bookshop.reviews[eve.currentTarget.rowIndex - 1]; + }, + + newReview() { + bookshop.review = {}; + bookshop.message = {}; + }, + + async submitReview() { + const review = bookshop.review; + review.rating = parseInt(review.rating); // REVISIT: Okra should be less strict + const payload = { + rating: review.rating, + title: review.title, + text: review.text, + }; + try { + await POST( + `/Books(ID=${bookshop.book.ID})/CatalogService.addReview`, + payload + ); + bookshop.message = { + succeeded: "Your review was submitted successfully. Thanks.", + }; + } catch (e) { + bookshop.message = { failed: e.response.data.error.message }; + } + }, + }, +}); + +// initially fill list of books +bookshop.fetchBooks(); diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/vue/index.html b/app/multi-tenant/central-space/cloud-cap-samples-java/app/vue/index.html new file mode 100644 index 000000000..f103c836b --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/vue/index.html @@ -0,0 +1,104 @@ + + + + + Capire Bookshop + + + + + + + +
+ +

{{ document.title }}

+ + + + + + + + + + + + + + + + + + +
Book Author Genre Rating Price
{{ book.title }}{{ book.author.name }}{{ book.genre.name }} + {{ ('★'.repeat(Math.round(book.rating))+'☆☆☆☆☆').slice(0,5) }} + {{ book.currency && book.currency.symbol }} {{ book.price }}
+ +
+ +
+ + +
+

{{ book.title }}

+

{{ book.descr }}

+ +

Reviews

+ + + + + + + + + + + + + + + + +
Date User Rating Title
{{ review.modifiedAt | datetime }}{{ review.createdBy }} + {{ ('★'.repeat(Math.round(review.rating))+'☆☆☆☆☆').slice(0,5) }} + {{ review.title }}
+ + + +
+ + + + + {{ message.succeeded }} + {{ message.failed }} +
+
+ ( click on a row to see details... ) +
+ +
+
+ ( click on a row to see details... ) +
+ +
+ + + + + diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/app/xs-app.json b/app/multi-tenant/central-space/cloud-cap-samples-java/app/xs-app.json new file mode 100644 index 000000000..f6adf5a45 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/app/xs-app.json @@ -0,0 +1,78 @@ +{ + "welcomeFile": "/app/fiori.html", + "authenticationMethod": "route", + "routes": [ + { + "source": "^/app/(.*)$", + "cacheControl": "no-cache, no-store, must-revalidate", + "target": "$1", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/appconfig/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/browse/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/admin/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/orders/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/reviews/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/notes/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/addresses/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/vue/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/api/admin/(.*)", + "authenticationType": "xsuaa", + "destination": "backend" + }, + { + "source": "^/api/browse/(.*)", + "authenticationType": "xsuaa", + "destination": "backend" + }, + { + "source": "^/api/review/(.*)", + "authenticationType": "xsuaa", + "destination": "backend" + }, + { + "source": "^/api/notes/(.*)", + "authenticationType": "xsuaa", + "destination": "backend" + }, + { + "source": "^/api/(.*)$", + "authenticationType": "none", + "destination": "backend" + } + ] +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/assets/books.csv b/app/multi-tenant/central-space/cloud-cap-samples-java/assets/books.csv new file mode 100644 index 000000000..cf08555dc --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/assets/books.csv @@ -0,0 +1,6 @@ +ID;TITLE;DESCR;AUTHOR_ID;STOCK;PRICE;CURRENCY_CODE;GENRE_ID;RATING +8f45cc39-df65-4790-a63f-634e151da734;Pride and Prejudice;It is a truth universally acknowledged that when most people think of Jane Austen they think of this charming and humorous story of love, difficult families and the tricky task of finding a handsome husband with a good fortune.;b834ddb0-613a-4edf-8d47-7d80989e1325;111;20;GBP;15; +3f09036d-3a1a-4eaf-91e2-5aa6f50dcfe0;To Kill a Mockingbird;A novel before its time, Harper Lee’s Pulitzer-prize winner addresses issues of race, inequality and segregation with both levity and compassion. Told through the eyes of loveable rogues Scout and Jem, it also created one of literature’s most beloved heroes – Atticus Finch, a man determined to right the racial wrongs of the Deep South.;b22f5293-7eea-49bb-9ee7-17c5de81f1df;33;7.99;GBP;11; +21c12f7b-089b-42da-8416-d5f67606f939;The Great Gatsby;Jay Gatsby, the enigmatic millionaire who throws decadent parties but doesn’t attend them, is one of the great characters of American literature. This is F. Scott Fitzgerald at his most sparkling and devastating.;a57f75fa-2bda-47b5-ab4d-b644570f29cd;444;6.99;GBP;10; +c49c354e-8c18-4022-804c-78025b529fb1;One Hundred Years of Solitude;Gabriel García Márquez’s multi-generational spanning magnum opus was a landmark in Spanish literature.;1d2ec887-cbf1-491e-943e-33a2b4f39a6f;55;8.99;GBP;10; +0c1ffc7e-734e-4c1d-ba87-3a032ad8a5a0;In Cold Blood;The ‘true crime’ TV show / podcast you’re obsessed with probably owes a debt to this masterpiece of reportage by Truman Capote. Chilling and brilliant.;c0526b1a-9a75-4a43-9133-163325cbbd2b;66;9.99;GBP;16; diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/assets/readmeImages/BookPage.png b/app/multi-tenant/central-space/cloud-cap-samples-java/assets/readmeImages/BookPage.png new file mode 100644 index 0000000000000000000000000000000000000000..41fd37a7a2f1a641ba76216b74617cba4770996b GIT binary patch literal 211617 zcmaHS2Ut^0ur`W_sEC4yNR_H0pp+n?DoF2DT9DoXfzSy>iXZ}^_byGON$;R^2+|=y z=)Hx|TL}62Zu#$h?x*H?PO>?>GrK!GXXc&VIl(GQ(xf*Z-6S9&AeEJoR3jj`?o2>H zn0w>;a#5BvfQ2Bp6ko5OXWA83BPzaBMuWiu(G44|o{F!&m%GEV&0o zHibB2W)PDMu_}oyV`f0YT@CQp=f!inD)(NSy`_44U*F)0&Mo7gRZjq0x5}P8*);wc z*aMoo=W_fD2AQedpWXk}eX3l$kLP74P-%5jvwEOF$fy^^5pr|SjE#lu<*paO70H9r zD=xxK`aQv+w+X*0Y&0Y4g$N!E3)prVk|`#Cc>Y}SU0$dKJxq6ig*^d?wL4 z>P!A+_+(z8J%;^>4aE%{VXmif?8T72p&6HzR`!r#0%djuV*g7l%yF<)uu?$nl$6)) zab)!E^VbA7BpBE}5y5|uyvo45znjLPA0sptY6y2KRY>9LF@p}!u$w|zJ?qyMq+!y; z1RdL$wn#Te*K^RDq=2V-@CP0-KGK-ptfzW%%mmUw1Q~<5;0KZfYitB5=KGXo4J0(? zTOWy7GHyN;Cw@pk@ty=c*rV^u{yvK`=);Y>gycVke-JZ8kea@K{O+cfACt;efL~F@ zRSjQ}_hPTE!9TFsUro6}^@Gx$Zt6OjxWF1A_m8`7#8QkmS|l_+-B}k8jG#6p6nyi% zi{|EsmW(G)?#cNMJtoQi5cj4all<%bZy#JFDhI*`9M*0-k!%EPzZMxFICyk+jrj$U z`H!>jg2II6KWSgxhx@L!tnXZX#lRJSY+bhJ_q=Nt(Emew4rMQJewAK|;EfdDJ?6Ft zMvuK^u0;i8KjtwNR11xHJSrnH_GqqT=@9S;_RNjln$PZEd{mJ^&4 zZuWXBFt5-l$l%R((#2gjx(3pjTMWLd^Nzc3PtYg+C&MQ+C!*)XR}~Q-GhO!^ZR>yYU)t(j>l5OCNdHRtvbv~CXrG(9kO9|iju?n z(FKV)wXgR-tq4xM6#auY<4O>fEY*7_LxXLcFQ7`F5Ri5S8Vs33)dwE+%96t=Rxy zc#+|odj-YV`ab06Q~xUxb(z(fRC&Do2+NSKKPsGeeplLj%`Cv#FEKEBa5YF~;d;&BzO1|2m0J zt#LaL-P;PCX@!Jn=kArC&-VDYhve`|49Lbpr-124gi9wVn>nj=C# z>vC$)_M65p-$fQW7lv%Vb2U7s+-9E=^QiGy@}S*4X&oNp9p3+7fmaAgY)OP!9C=W~ zb{kw^&M@9a^@ir-?W31_^QRhEVWZ^lL|c!Jc;S@n{*Dp*L&zEJ6Z| zM-q0Y=!O@$IUUa!*iwk!$t4nxH<&PC3^keA>O?O>!n!hL-lQ^ux|L1p_AHrq{eVf5!YO z>)E20x#UVy?_l9cVIcU8i`^KFLmu~ zH5QHy-NoA64ZYs#1&GiXuxPsJ$fh*o1RCrmtJA&eeC{0I?08aqUO#wfwJ8Lsu^X?v zSFKvM+sBr!h?O6e+n0w41VQYkTBg(*meFIUdfc&s@tU^Gw(8(bE;0_tj9s1A;!!{4 zm(Qr!rdU#;1DC?-UGKd2t6>IP28Wtwnyi}XO;kQUuC4>y9oG9BWg;~q?y$7&Fcj*7 za5HG~(R5N&5;v9wTX!st7SrC;(u0X(egpz*lvD-mU!2YzN?ZgbZQ5?S3RnVSXs-uR z2BqT@_7+o_Go>ftW$-b)>CrIUpn}8 zMG?!+uVnY?El|_V`oQU8eO}9Ib1w0Kx6yVVMW3Sh3br}5~*FkS&11XR=B z=)8PXh)Q)e#!R8*wl|tMYEVAhn==Ji_hV`L`@(Ia&%GsK8b|Li4u>UL%>bu*m-MY& zOzj!VS+_sP8xu0S)aWOynip)iQf0Yp$qB@a(dDgWyV#6~VR3(v{2W(dBiCilYJvh%bN1FE7cA ztN&el-8qBszsrQV|1^B9E+H#>`KxXMH8Znww1hbMxG-2>vO-#EymNY|r~ov9*m4<} zLX6G0+-&XtAt4ZU16~$w&76!F-E6^jjzBjNrvGRGye$87o12O8Kbkn%h%miVRAH2W zK+PBdTrap@Fp1t|WMmYEnwkUEB&Gg~{PLd&lckfBJ&>E*)zy{Dm6rUD~KKAKYWdhAg2a=qaG|GY0rh5xw=RIze11M5gy*v+}X4wRz)l)i=i@p^JuJEq(-7Z!muN)0fIOBB=b~sDr~_+FTNAeaOB; zcjd~pyW#|Y`066K5(T8*VRH!nD<@gHvp)^xKgJkwKX~i-Zi@B0} zVpkIbl$y0=)@lUe`Ts&2^USv*3iw5qE`Ff9rBZS2wr5y?QvODg{_VdI1rQC%Z-9Gd z*1Mkdr?YVSxcLVt)o6bY`->=Ylo%Vc;qZ}eekADqMQzZg>Fe6P^X?(&fF6sJoI&-H z-=Eh)oRKR6q}CZa(%nrpQAk4PW2K#yLOYbT}g**Es&N$4PHm?Yjcz&GW+bJs9e2~Q;nc9Xso+>cKe*G%-So)vA?YG zrAGZD+mrs0?uiDSzKN`)saibOP@(liwg3P+2t0M#us+4C<*?~wO+4K17Y@nOJ*B1g z_E==^-#VhRF$)yTGW3u@~7FtNGxbRSr*og}HY=H}ICy4(}O zCLfZCi5?&^Df_D+bs3AY;ou>6q-2`dx2BY4i$i0`R}=KjFZj5UU-1@FT%?ofBXzpp z>1NiNVEncCypQt+GcsvwX-urgKy8<=kCj99nFKtmGh~ua;5{LEav}2!Ti*ke;B3in zsLa$s0BXv~T2cTCGohv=TvpI)Sn&?zvAS=&b2Ekf4-d;fs$G>Mo+O*92z6Yovto6c zYF9F>RZXL=>Vgm46SH!78csh7Ter;{q6RSj)uT=?M>d-3G<>X!MjaP1_W=ubP^e`W#`!P3c z1Cih95Mu(7;X`)ph?PcVC|`jVR|~)OysqF`k!+-w?pJeiPWB|LvFnO@)QNA3 zV99M+PE#a&)K1;Gip38F$Izb6BgWKxCb3f`CF+@>2ZDJyPG9vBo_sR`)yubjt_n+C z>}A+ecb{;wdbz^8ADTLFIxXuuaOMN?Vlq6${cQ4}j_z_l9YmS-YyDb|AUuY%I9qEJ zJWHLdjB|liL`^uZB6dofyDJhMKkGZUdN`Y=AHihGJ4nsW+wyr@D)cH$bs}Bn>0lL> z&tTQF>Hxc`Ck&nw0{ZQMKQGOV7@mKO(EL4t?K7bSRe^YPV~DVjY12fGa`3KHN8!6@ zZbvBfsD<=G|ngyxo-NT zIoF32;*YAgp_bLHpSN6vZuY{UtEtu9DHG+>Tz|7I-$}1QhXq#)+ifJHU+gXiXFWnd z@YdV{bQJ}B-*m_1bI034tma|Z8G6xH|1=pSV)iSk<>}FsclE_- z-fI>o+UqudcC}TR;<~bQict+f*M+(+@-}M_lP2gj1#rdFj z^aXIsqi@jBeRSM1N?rcse_S3M&u@e57QhjAf61ANvBD-;4Sv%sdQP*yzZ@6j(G?Nd z+*4lS^Q2WOy!v?R@IxcIPA}ezm7QH$Dmy;EmpT0lVkBREIZOZ)vYj397gvdr z{KvwxS!|;PB&2@n#qKcy#|oa8q)n<_$D43l)!VR6fOF*v%%%EL%3w|#mHlkb<0x$a zT_5u0LsBqHWBd)-Dt?i`aJpehkJQnlwVe)nq3PN)9p22iPsJ5Ub1`aQ*L3~{)^4kdF-I8Ho?ksS&Ng~>x6)wwQc@2#TWyult zEjHd!=ssNz@B1ET_e*BGCR!T0{H)c6g&${8>hGmKvOJ{zvWgxntXl&P?zLs;fZkZB z^{b^04BDjgLLwCs_!PZyUf(pu8LvZ(mD0||=r#6b6T}qeV z$~W8-35n;bUj9t^1-&u4OKw$caKZu%ONK8Au752aDz)9T*BnBpi8MzUwFZuRC_WNF zEjE`qSq&a@uakWJ8{`vXxx_TmdFsO~A=IV&;^|gHdq2~c{m6WxRUMvuidvw57)8muZA9aoPy84bdmBE=)9iX(tTORo!Vm4x`K#iAd7mS?h$(ypmgrt zv$8B3?=^{Nu`7y?x@MKcKu!lr4u~_-&7~$7=2FJ7#96QwpuTeQs4FeAJ>><}`5=WjFCT7J6DlhTxA+<48T4G`M3u z@Oq`ski|a`9@nWT6yH`FCLsn`Sw%4SH$GLKb}Tx_ZK+>E;eb096o12k<>Gzbo$1L+6blN${`BE7IFtJZHgRtg9PKpN22Y=J-&xXvE@vuMtuHfN^nPcITm)4QZ3qq- zYc+?;t$|6@iXM$B_*vu}D!X_VyNi9(E_uY_8C7W__7@OgnkGKU?EGk3O|=fQDw4N+ zj-%-+t32g_R#9^r?*V~fy5+j8K6jLYYx#V$pFT-_qaeLj$iwWka?pPk00(mJO0Q(| z3=fLfT~q$%GV=J(nk~LUk{v(tvfD4d&x)c}C{?#e51||B)lQj4`^q4f6VN~OlH?1V zw4kTVne8Q?V~!3arW0Qw?GOaZ^4rp|Hzo&OdZmUdLT}&XxjoeVb1eHoyz15^49wT% z(k5QYZoHjRA$dnJV#oa(hA*+v$>4=qa`GERq&EGeM$!X;$vkoC4KSd8Ad!P}g^VRL z`bg-F#Gjq+-7cqpAQuM`9AiSy@Z3Nb8MRH!7X=S1kP8YNWjbz}Qs@M{Uodtr!}BFJ zSr(-rYgMzoCl~m6Q0KQEM5mO7G&k)R1e;$|&dC4{b{u@PQFzlCI-s*dN0KTjz9sRe zu=+CAEu`$4z?|%#Z^`Y!Xs4GHu(xTj!ZdVcS-}tY6=*mG3Jp}vxp}%DHG_i=0ye76 zYlkM?hm7ZsS)8JpHAns?uDF}o{A!&uuoq<=@jD1WW>$UF2ugB5>uX6xheB=D8ZkLg zRE*;V4k#Xks>sO2 z?Q!YhCkH;Aee~=vK|dpwXoxmneNKc|x>q-713V+TEVtRq>lAn16=O3oOIG{0)q5g! z2@#YQbDHlvCfTYRm`sDofvCW^a;Cp%Z6L`%%2exO9yt9VKIAX>;bQp`!X5H=zOo+0@j-)YYcH2_x&8%!cU*s=fU$Gx*W>OkB;v!fUk_ z@|QL2dg7a6Rc;Oege)yBeM+dDc)`)*X6o%TuCEeNBZkEq_;9~4JN8ai{(#0Gse?s{ zgAqh!(ug?f!`G|Eza8TE1knR7{U;KEw<8mIE#$nty#tuJxs@LY*geOhtJ5z*owRo{ z-^AGJ(#oWpQL&DV@Jk(?#SpeHkJ^|W`Df^#)t_W_%r;IZGWa;}YVMJs1k#P8fmKxP zJ|`q;C)*hcjkpij>32yzU24MFOvyRVSQne@D`w&vNt4?Kfz|zK5{OI}-D+vX1CMLB zes2IxKYU^i$+3a1Rtzgew%dY$e#f^uC@r?2+G{Jaty+&lg{U6V{BG5pEYy}ZfZ?W#&3nOfek0H@~ zzi)SfbWg4lYVrs;6h!oUAHX9eF1^+!y~xlIbR~Ep1Q7S|TX;-xy^b>G}4a_xr{5Wrh703^$T@$6UFl z(sA4x5ZC#;GPpT6H12kZVHE=l&To|P+^pP3RNMRy`z1Mg;(7Y=u7g#N$VS{UJBXv( z2^Wo8n0953{k&T2-+K%3^#?K*G4Ogq)L6&O z#wVF!R35$(sBHT{2FwlZBmWRU;8%XGj)&pW*U^ow{zpe{B1(oF71zvsd{mB5*UUDG zWac7sL;?BHe2dGoe22lj#-hp#_Z}Ay74CARdT$q$c3~HrUAJ3H4kIzDV(RoBArq3n zHB!FM$?Z#9W!?{Tkl?6&-dt(5_f!qP)zc)c0uTR@IdgMPz3jw&DG~UZ*qJV>^0>6+ zaRD8mK2qRflGX8G|9v&?*s$7mqVl-e=}$9_Be8rw(00WZ+Sx(eSk@?CG)y{;!Qbk< zhZfZ?;Y9CxW8aIJ>4UkSIp9ADt9NGKt&}I~XUq(hmO3Ja4Zg*e;_vOAReMKvoWWiQ z(Z38gbA>ip^q!sR`dAr24z~CXVVZ$WX)T}cqR>H=X!4xGx70}=J zhiwYe(%`#a9E;qj$B;1e<7y7vA6eDs)SYNqImn^yMrK<(<0!wE))M_>j zKMwkOhxPY1vWx8s4cWnhAHe+KXR<)V>(G}P5b7t=FhY90cIKp!#}W_TwwtUT4sa(7 zU`q^pj}SV?oz0$KXUnyYtuC!=chEtV4Ror>Gw`ghvhDu%6czH+%;hF<8IkZ{TPa{adgEVrd?uFF4?C{ zO@_YTeh~luj6eCxFyZ;fvgn;LH`DMSTpH;t{FGQ4-tXde~Il9{Loi&1Y%bG<$()SZfKh2<)BJsw;A ze61m$%qUS&mw`g_oWY!!2~}Hj9#{vtNuZfMWk}&|&H?Ubp+RZMU`M z-m4K<5W_h-~(bLIZ zf-YK!Ur|}J3oGf`N8pp-Kj`E0_ly237hrvrMSm{P!$-kcyE4c=KIh$brv=2yck)W@ z^{ABeqlxv{`U!c#>;7adW@xwhG8aGl#Ivu&qN?GA>kKo;l}(LR_|16EKOu&a4Z0i7n=rBs@-~>nt|FC$ zf)>L>2~l}KKLp_dS=d)+fI28W#;5)Yve-xn&F6aE5z0evbwC`_M)n7rD0gL{eFoLT z>nUe=!MLYD*Vtem7{Nn-K+JtyEY_MHRCun~uK0T&|KXn}`l<9{mfO~=@RmrR9b8O6 z?PHn1Dg*tI{PP56ax(9t-&2am-MUM5nD+F3=*VM373)1BcOW^l@Ks+P`iXIdn^UwQ zvS+Y{rW$A*zHi~^-`3Z+=-CV79wzrW|45$qOSC%8M#EYn$9*1Ud&@mC)o{|KTwb7D z-n2EQ@HT3z$u>owf|@POQc7yPQt^Q0Nxhr3!=XoM+iY-i{Y6<0?s2~}AB@Q{E`xUS z>j;d@q=o&A=z-fBm0I8dgW~u#r0rQPXHcg83?|>g8=@rE_T1NyDs(g%FUgo$H z`;4+D*Wte6XNq@~E?Euy_EEGj8|8K9S%;xg!Qj+|UOBarT?qp)?O>s!?Ng0ANSiP0 zS`30SCH*lcRLzpr_Ee6!Na-5|Ykeysu)$u_CZRwFVD< zv!K3w*PJdhBb+WArqa|ZjRhe~5_Wd^hMPqn3HNh~^mB}LOeUqaFHlW;Kd@OtZtRw7 zNLA(()<#zHSglm*MQnsmD`WT4(Gc94;qz3}0aXjZ%s`Tm>#q z8rD~S|21{vgP-43n((K;Y#Qh0$Y!P)n&QhUL5qfUl`&VcR@T@MTK5NDl+q-A$(wdx z$VsYO@Rr}l+FpW%+srnYkViqO-I*_1K~cxk-sQW5zp?Zg@2+?S!j)=Q$XVLy#r-RY zMl@`ZkS=BH!$-O78K?D8ZMSS&hEkH8=WkG*S1I~@zqFVgkYpN-Fkz3x-q?5>{Yhsf<;Gm+#)^S zhPk7ERhx}`9gG~4rgx~(hYo%mGOk{U#IZgt)UTE6S&EI6qvVKN`mQ$NGQJbZ<1oac zQ}1Gs-yq6$^Z!WC7yQ89AraivN#_80gdMua>f=QH!Udj!6F1bUFSc*%ceZee(CeQR zn$PclfKDrj*4fz z?mVFio9$Svjfw6o&ti7wn=7Il@|^U$BSjrvxJ{NB31nTv=PXkVA!iSw3QFo<%B+oi z(@}o}0KexhQJ(dN{+#8GoMl&<{DQzOAWCvjk)2(6>0V85J00)-TjA!e>3M8 zF`mRf&&(>(u2Lv&fW8&58m`Hug~60nH^F)_V~41b-93BHmw>(OYr9elyB8lQ_U^T> zFn?io?q%i}O>y z(|xPFBvrxsiGZz^w;@ZBooV+KxAdL5&GtG9xMhcP6^DQ&Hrd0qrN7zH(UbT=R2U+J zRHj%#6hZF9wxR?g^!m19%1#4x0a=C)TLUV7<#i z6UyFoDC<3=*}G+$mFS1gdab^Ukw!O77n{HuA||ghJMj%hRDj6^SNs}043h7OmL3(S z@t+c-*?lS)mTI{*#xfN$TFw}R$0k;dDFjwc7 zxOw*hN+wUI{vxTM*M4AXE(2I;gCIPfVO{Qtjm=ejB#%2g^sl4j(C&d@e4a2%!=uuD zsF{j%t75#4)>-0{@+ZG(7MP=^kAL_q1-%xVKnu)xXrCR>Fv2SASSh^IpJ*0nM6xr$ zUcE{OA(~6-w8jbzIH*!wi=9MHGBS#ln=kf`>M@9Jc3SSdG-%W`9ubi_RIhAE{b~o6 zuUq-qN$B9N;Q4pEp<>(QxmVLNtH8=>e)H_1p=E?~d6!zLr~CTu0ma*+AlE|ON;%Q< zHHy=2mhO)5bVe+?KAhH5g-UQ`jX6gx$M%@PVBY3E&A%Q(s_$1IJ{#XOj?bX!v!-h& zL`Sold0VWpJ*zp^7eO1>69=E#CXL4Uqqd%%CIb-M&D=34LmDQ-JBg2HXB^KNfXDnk z*4(SKb+!~h58p?_&&E5ld=H$R_(oD8WYK9IE3+$Jr#97bE-`%unA`E7R`c#|tiY(b zPUTXZ2=?8mkYjOlW4kQ$!ppqZXz3uthee`Weg_5Q4~Aa-F0kZB@X?&Fl2m*2|B zYpNte9j>rVmaORac<``ZQgQGCU3t8rcr4I-?a&Q5lgbSOD7viiIIcX`X*3UO46L_n zW{nzfpvsj^gKalVQ=&cgV)CJ*l}NeVUFcF2;d^6nYQ-y81tM;{SHe+_1F?v;7$HP%1dkFnb% z#vPRFdoT05)Z0zh@pyG8xTC|Wx5VfaN6h<0zy@{5{4k4$A*cJRsKqHVi^ZPqF&Y3k z#s*TO6L_1>Jb7)znXs4l^FcaW1APO=4twj>#O{{#|Hb^i2bZ=6sJXdpKGKWDu_Gwr z=~%Qyv00uXPPyl&87n^@C%ro{-f^OSWmmlR^-<~>N5g$>2D{Cw@U;OIJJGBxj-KfB z@XFxS+12OqW2E0uIH1Q`K_;)M$%VP#H+2cYFJ2Of<)&c`tElf!{H%lilDUvHycO)+Q2x2U~b3o0n=bc=sf8p$R+*z!? zS`vZ8D#oajf!XMiFvf=XRNrXU5(W60SF5^fKD##JJ z$lJx};u#p-#;(l$S(ji&G(&B!^kit(WeaIw2y zRS{gs#Cr<)ad^@FLdCVM`u>?cgXWpNT0t#E7n_+WC4=LMRl{6h3h-ZmOGcgXhD@#{ zexiRkN3FfgrKe2H*_I1Jn()xds~vy6yIuKqj5}NAUab}Ef*B{T!C;k={oNHYS!F)) zj9V&GHroVps+;@EkX3!9C}J41&Drn63$oVc;O_V02hHH@p!T_mAzFx{k_#pp0m`lt z-ni~8hR`x+o3T~II+-U2nb!-op5^5p940J60&>zK8f1>H^Q=8x{#gb^OQDVshUPsc z4Dh&WVvl|qz^-2HdZnT1MOo#~%>V(u+{&VODj1%PL!kvdfw)seLgyvYi21mZ)YP;% zUZ}9PCNdcbJiC6MMohq+))s=wu`W4H(>R>D0bei-KXIOGjP_WW>`nJRAr+6j9f87( z`xDoyGNs_s)=$*?M(F$ zuk#BbD3Y%FdN*V0H*_|I^7mD05p!_QzO(3iA3ZT}+oz1_xt|hSM?}+jHu*TNSelm)IKXVlNst%yPUh316}TM(Uaz`T|6T@@7rD^{ukspe|d#wXN&;+ zdAZWN8If<0G_g97;xJ%01UUgG){i9ToAw^C?t$>KdrM+uQQ>x?a^3)DDfmo@gMHP) zhJRpb7!ljcmovi27F(gLF82qP%>z_^ZBS+#4C_`cFZYv0$t#1IAt1*DPy5A4=wUhv zLCWpn)8-ME2txZ~8s7y1F1A*!juIA+Lqw4$tqi|z(DCL>{RmQuV&`6GVonz|Sm6dS za~~uz8lc?OS2oM7oz?|Bse&NwV0$N$UscjG_56*WcWjx@$H_}G z*l&JuF5W9EO}STln_{~jS-F9cpLIyqD(&R?X#!e}nT!7sz9Rtt+`<-myzW+0#<%SH6W=<_)?+l9wyg{L0>{Rjk=Fv*a1wPtAy>aD7D}9ZVuLOsyIW61ddYhNz$UgKCS>>7ASHd>0IoohySN}liaF=SUkV?wXsoe-XJD#0xWOe$$XWApa@ql@_j-hD~=(;i#{K3lFiRr*e;?P5*t? z!TP}d%9bf{)2gzG%g;qZe>R)m7}Ju&M9XNPok!W^N-dY2m0I2o9!sT-fd`l19n@&{ zg_Em}CSF)fVT<%Vw&;JBgX2!rzb_}Rk7yO|=1LdnWqnEU>D^Y#1XHg!bQZg4^i%m; zjI#`^1&1unI39;J2RsMW_H8?^4zwf&ZL!r0d^0*`7|t*C6afd)8c8j#9XJM|N5yrM zfL?LRKKs3?6u3DI4u?%Acr@1huX8mhGXMb@;>9qPg9 zm^II<%+6gWiTydpSAGRn(iugs;KuI>v3<-l9Qf(;F5pb!g>k2tp^lCG! zuu(0-mw4Q9&C&V6sceE$Do~D<_hS;9%Yh*95-LS7{L<~8u2E%%rLl$4pj7#&(tOg^ z?t_ElbSteVr&$~Oh;C8!I15aH!yEUj^d$3CIPCJZA;^qwX-p#>I7naw9-#Ct!1n(- z%qj)(MWt@34NK@8>;6>SBAF!4B;KpX-tFHGcp%&gZP zB&HC1bGc{yTK`Ymjdsv$aMaiEM7izETX(*9XSn$@14rVqGxThR=R6Ydsrt;Am&`!; z+V~HJc7XKt&@>KiLubqLh>XJ05L-bt>1b`@ZO}sr63{qU_#pB)Wm&K9KuY`LW|83+Z$2&sl*bRM#QQKl$0}_72m-`?+b~aaYb;@&p zUYrDa%f>GOop09AKx(IzW?eSA*(X%r>^ibN+bj<_&=D;_7Dn>8oB1uNf2sO+qJys( z+uYT};J&@-np&5n@&cu4`6GydfaRC&H2fhg_hk~(b269NSvJLDpF^tJ(@;3ipaSw} zCnyW77sgs)r^0OJWj}PEraHAT+>^&LN&o!dc<+}%r)+J5zEJ99*a|g})J8L^O3|iA zT1+Y0DEdJcOn}y^|G;8@E1g~R5i|buea!h{fQaoIwhMCh1PlDs{>qEf)pD_}(G~jm zqDe-9Mo~%n#vKA!GhGt0irFa*=b0kxVMPV2QEGRYX~m&kkX18|t_!Q9mnR{ovjDw5 zk-`(PlxcJBrdH*`-8Ox05SW}B07|k)v)VK5j<^ZYgeweik>@EqXf|#3_L1~--Gdgd zCw8=Y?&&N>RN{V|UzZtccFtC^pM5&{F}%9=hz_gw7GJh}kGDO6D@!UYP7l&N%%%>o zoixq6MI$yZP&*c?e>$NcTV*-8z@#3@`EE|cQ#m~SrDJXbt`Am6t#eRv%SoqZ0M-;* zFk&%1QlzJSQ2S4UPqjpyTq2Jd_)ruE^GV!2zr{TPjqf9_Yt5Fxy0~BwB_2IwVs~yH zZQl4QFzX>bBWF*#uD@E|-~67`$*Ip7sZX6E&@>+fLd0>CeXBc_%@f*g>KC=>(p(#X zY8$}(pBvQmqK*G;fqlfq7r6m1lILhIaj$7QO}Sw~O8^`&Y}MEY%>LLgv+6owdU5yo z6uC9j|lO0tJHk9)a|&!?|tgr)G&a6 z0d^>;T;q7jY#zraN%qg+&t%eG_O}ZfHMfXqO&3^k3TY-OQM#HVr^%ao)55HKu+_Az zi@BV!{>5hsN;O4!d_1yWq$(TN7Y{_kCy>eOOLJ8-UlRy%gEG@V{`-x^rt&<)rsxSn za$ozY7n$5Xpa3U9(wobk=M5Ji+kXt{J_PE81`b=Vc%qRywwsD6UMsa5OVW zhGMI1r&2Kk&KL-`N3nW_Uf&-sJor{ReeKJ#HpmmCTd{MIwGfyLi5B(3PT-OT1_p)2 z$S&HeMor)%E0(pGZ6UDx$)`x@uGocHHQ5F^)YTNvvFCw#5G98kIJR4n2 zml^%0$uhl}!sDEj;&5b$K6U<9y|c!A{6%2aEp^K}N<~?8S_0&=Z!5&AU+{oaQktXa zawoFR&`ovc%(~1Rt-CJvK11ZZOrAR`gsb64>gRtSN`ZaF4~GpSmloAuuce|wdH9NX_@?J%PZ-+&Oj8WUgJ-t(cIxA+oHFa+7;@Ot}?Rf zsgtH->2butWyGz)um=(>eD698ucAIl&AT<9D$VRM}9 zQgxp`-{jcxR=H(klToH~L_!FfZ1S{|c-c*8L&Ucxgu@~;TyeinLC^-necirGpBVS% z`PoIHvYlJAZ0}lp4x9A>LIYLrQ4hfSJJ-yhXTclt-OvM7=>&@jjhJ{tSSwu1p_{f* zSaCq#$;j1erclSe5()D9_*{TllP_{lvmdhMZF`)jt`sGYcduR3Ft=MD@a7i0s4-dE zOl#cQcW`oo>)mP>CzQgRF{qC@;)W0@CIPVUe$d_4c#4I^Ix}_ZZ?rCuo zO9`c2L6((Tqg{>dH}s>}##Q<}YxO8#n1gMY#bpNBhd%G`CFh-?ALLx~HA)K`yjthi z0sTK*N?&Ekj*Qoscoto5Ks7g7U@Y}VA*)CAmF{2RwyQmby93_kL^wu^v%(1v)5zPI z_rgqXUnVV(;M!;$C@}rNz1$rfuU=I%%!V#SlE%V+*v8=>r~GiU0e}xhk3W zHt>;&FSok({P{w$m+23tf{~4loR`W5S9@ERxiBS9xV_*G39n zOjcE=#}DzUNjL9Ls}<`DTB(Sg`tR!t8E6;ij$Yit$X6M3D}?0YtB#`j+~uLE>mb9+ z*Hodfxx{B;}uEz3c~142wexLFtedUN+IzGEJfpr_s7FwI=-q9hIt$ z5VRA!JbRku!iG7?LcaIZizhZyB44X%GWQ;&h(Sf+)jnMeC)>jGfc(X)Ge4;c7zpyf zKtC?GH39W`?wQd27Z@X5BxDx7FbffSoID%%yF*oRIbS-GFAYf|W# zmCBhI(!Th;LlhyKZ1o*dwI*T>yWk%W+9V97UKpKgw8Gnx(L#{}7PlH))s(%gqeuxLy7hwz7tgAjUuxI^%OxIRt|`hrivTrDrHrVdrA`IVd$FZ!cfD7@e8wEQfy{kNOmPf?O}N5t4dI(15G z20?GfbNgnc^(8Q173e!=(D0234PK8#(&W7RE=S5dL+iMyAgGY4gk57wcEdu5aWsI zj;ITe>NpG{obcn!u)LpJt?ZArsESK;mVH>oq{{$NrcSrV%MLLx^^cVLdYbY2 zf`@q<`OSoRn#9JH-#o(U2-WL+t~V6Q?zHJq{=X5*f1WjWN%?Yq3a_s*YB~AxatK$) zQaI~}T=W#m$&=^w5WrY?gWpIWt8}n(ocSID9?Yf>gF9vD7(V|_!3eJEJXaYysR^Np zJ9sq-OT7_PL3>kr!*bu=Je-GKXPBX(|IIE==$8xE;TN&ffj~x5T=)SB=G<7_1;lUHSHegYeg*ZA_^iUC`b_mrAkXwlz=n= z1?eii_fCk4s0bt?VCbPqQ$TtRz4smnO?nNT5E7Ey&3Dha>#k2d|F{-QvdNx3d**q5 zZLG#7u#GAa7R{kCf_Z_D|2V9Vqh5!gZW!=?0#%eHmuNl(ff@H2u?>{_asg%WDe$>b zMwPoKGUWseSvZOoqi;lz0x9*OrlsX{U3$C~jM&NCqk^pKpxy%IBHiURxDD_(+k4WO zx2T?ujtHd-?2i{u?4u?OOH0Uf6#3_;&mU@3aQS~8%zh?r%|3Mn^73ufUbo+NV=ANS zXu+i3gQ_mjts2@iR6E1dp?ogo9CPAh=Eo2QlFCts6#Ea(0%g!|iBy=&qfA+h<5j#mk@FpTt@S}6X%-;s8QUWHy(ufaLEegHMm%rnl&?=K{B6jH|tn$J_+9D`@OuQ{ur%$EBKn`ln|%T@Bfft=j0YfD&^uYe?6lu942sE^+^ z(70%-=INimrP__mQ%=MOBzHbfv-h=3v&TJZAA~Aw2K%mkq$Znw%!Sb9Z8)X*!q;3T zUvv0X(VDLAdeN#TFIf=2H^jTQh+3f!topQMD}ET(nB-PYTOLfe-0#m<^os#nnx&74 zg+1~-WxaJZ=fhoU5T)}NTyX@2Fd>&|SZ1AkNSxIK{2F4*o=eyIE1q>Et?vg%*aLg~ zmm5b+xNGCfi8QqsF{$b8COriU8if$P0l#7nrC+wbmSBrVB{!G{+e{@>OzM0tI-F;d z9XD}XJi++cjppjvI~SdbjI=_-wOE9oTSHfW7+30^rbs;JQ%@8g%GQnQPGF3*RF4}W z_?iONI6Ql1TTX`v<~f))BV;pR$rz*HmwPDXk|L3*r&$qgwlbK-S=CIWuep7ArT>4k z0NQ>|^OyrvFF|(Cz)cMjBj%AE${}OG0L~0Ke@La%&wmv(x^BPWgxh7?-s!0svB66) z4V82y_6Ov7763Jh8w}DhC#YjlYS|Tv2j737o>6CKAuW4yO~ zxtEyK9I`gk!WvjG%GSt;Ib9N81b*hPjm!Wqu{Ktyk;^9L#*ra~R9#yR)~MitP9?T8O_B+v?K;!WUY08N@mFn|H#| zJ|hHy`X%pqiQ3 z?X?|IWwi;cFNKAPg#BXorvSe&(9%&cJE`#dVDB7wuT@zQ*?87LZkj-@a zFU(6$1>Bbv85};1(_idJuSI~{s`BB}VjTnJRuE3JfnP<&d##)P2m%i*6{w07;7NNR z>x_oV#qKfu5(j6oTZ4M(T4CL_^4!Z^09g4{ip_NkoZ4<*GvZ~AZj3Zlove0QG< z6B_%@5am%50$nI8d-=uJffYQ-$!elwy2R$`(oKv8bksbowYvWTh6+>oPml+h$A(6T zJGqzDE;4K4jpHo&#-manq5<>l?1Kh*jp9`-(}G3F8#Q^xtBeU!!c|L=4vsb>Ki>!& zRE@BBREXi3PgIjl+#9>%%O^AAidTor7y2jF3>PlSyQyO|B-80RjSbdH3_ri1XE@_v z?JCft$q?kpIy$)A!>17|41=$V+I2p)k1YbsZI602BKTyp`K#O|u-|~s0T`fdggUTM z-x;XC6&1!V-F`e`t)EG)qB9OMmAglpm{Hqh^_p!CQzHlE-Yghi#_jq_^v$x|>WRM7 zaM@udT4}KMYyN9oE~>!CVt!uFloiI;&6a_-1m_a;ROi}v zV{TUrW|}AzK#YK{!2gM`*~NN*JAZhnlJmN}U1+luOM5DmG%pV=taLfUIyA+}A9&6OXRk@ayG!6&t&_v@~ch5?Jah)3a#vq$Z%Z2+$bR zNwNP)u^V$OX=}^5>Xw!a7X(>~#OjEIntp-*!HlJq9)u+olmb;_kvi&#u z`YSwy03`*hX}~T11aJS|hsZvw$)!uyq)v8)o?<=YYh7{Dh3KwpiXTonc<>x{^gjzl z->!4O&7y>jZ8vJ}pAa4GuZGFVP)E$(N;xWKyc25cFH&Ll>yed=V^6*WsovCkR`p)& zPy3Gz^Ur(^2sj)2HG6F){A!H5&d(qKGMU+!1C=OIo7l6=WWQZ_N~Y(;r$z2XtlTKu zY)zuRsJ2$!4S0l$BkwYZuF=AM2S7$A$Tz<&Lh-obN9f?416I?v>IIoQTaD@+ER~}+ zt?t=(9Q6E9#&ffpkcbn6Db1Vjl~Q>tQjI;cED}cxl`MN=ctTi3nbfP73d(C+K5-W5 zRZ4A7x1ig}pa9{VE(!aibsxOJ7c-G;%=lF+wYgOqQ&X%{i66?%0iaH`(*d+V`;njb zC0ynck>YN{_JXF#RlDmGEeM>Tvg?KQFS@x#H#T6K;hb+$vB@1^Kd*w|pPmk5t$L<# zp31@O8|twVU(o?qg(JEoY(;$LyTh$>c)Z;sdq!Mp+H);Wc2|?vd0?bH)S{`kiiXVc zLwy^i;~2ZdKDTw#p706v{!f3@niigv*uG3(n<228FiPP2Hk(5c+p-YtULpVMG$niR zew^DZQ=vyV^1@sCaYH)!f;0$`;%kRN*Xf1JOe0J>MNgM<02_lgRxL1HCx7{p8R^FI z*X{X^j>{;T4&XH9+o&Q}%TLVe$6e}MoG807IKJ-6W2&KWz^jk(4I8KZY9Nf$c`Vzn z?(FQGdl{%1stinBbyV;8<&lgyjK_3&>`2%;xzQxHU zOxfc4A?59QKOpW|6Zcrh(5@Y9g<#Y9YQVR_k_+q4Aiw}McTxiO8)7hckPW(YC zhHXAPD@4OAJ%rEqaluk13IJi#U>~ayI9-A1RqJ{sG%P|uD|K;@(w2Vroay)wc0%BT zyFx3U>n`s5)2#T-c-a}tq3j{;9D||FX&Z+;qw;<}uW{w;3d(skMxzBb#%2bh4|x92 zVZDI}_ohOT7ZXzLN*k(1&D4Y+&uRrz=T}TmjtPG-&CB~$I;5WCwdLWkB0YSe(z|j^ zvs9>H_^OwGTD|C#8aI+RkB1t+voU|wFaxuQohdyk3+eldd9QVWn!MqWE)v@*X!8KN zQOpa#ka>Ap{qGQ5dQG9PRU&&`7S;HZQym&YO#BMmY#&&vUX=Bv0{4Adr=c7>usZd{ z&b_7ZH*67TmPWRYU#06=AoA^_$~T;HJ=Kis?e^a{?^gm1lIY^hFwwjQS&bD2%xqBd zQlZoHKlZc&fGXZ3x8;3DBRrLh_)ww5gVyRMT8j&8xklzZ+gYlXy)TpCOG$YpIB|S` z+{16V`d%)>e~I&seoPuXYkl|x_0Udza}I~Ijt7tx(xyvpr|e2l%U7R=N-JgeNiF<^z|1yR(D{cuWaD`i~lu0W=K8e&t2&4k_o17o5b<$LC zob3?I}C^L<{`sa_C=l!$wVy14| z+u3G?u^fnc3(p!Bm}Oc{+C{!YBiAS%O$mR|;s4t!Dgw4`cK%oM!j0FTc2cN}`>64* zxZ;k>3^#y$s+S&+Jz_89EX10+*x-5gPjJ!E4eOpg85}z^Gb`n)?60u)DBv0nw0ojJ z5_S=+(^7p;z${(#st-?*8f;VPSK-bcBdkaNj}P)5x7?|Za8|^%kX`KTCp%3AlN-yX^d!|> zA8U=5bVEoX3;7~;B4-HoGjS&wbop;zMB`1-Y%1TEtGurx-x6iHa2Gluc-FBL$Xx7T z^8RsZtQc2GLmy~u@%rfEeF#$cPbJ0~?#~Iw9UIjPh%cTvJ=nKt(xG@ZB_h3HzKL=! zhqBnN1XlA61NW%|@F$MxG_q@PwM|vcH(UpB!V|_gGEa(u{cfF|<{g1wt4r z-)X|C^lYG!zB4%=|mp^^}z_jjt(CqZJDJ0fNI{XIoMu$sR=IHPfF&YnmE zkLx&i+$b z=Ek6mx;CytDcI4w?DdyNdGnXj z%q4bFsbtdTnZz_a#ZzU~YunonHz{W$FT2JZI!G^Ona?EaSYy~C9tr%b14>ZrD=(7- z>(4Z7Nc~}zJ(^%9Z+Km{uWuQ{(=_t8Or=x!+k8S4z-?!)c*PsCmRFCgYM~FdmS3c4 z6r4{6gmKfMpDnp30!q^-J33{N#H(oGt+xMT5olEEF1za#PISD(<2>#nD`S|#q;Mbh zg-Ku#I@|W>&}?I%`w56M%j}=)Y?vpb>x@wjN}^BGC(Vfuj#fXh6nM1gusa!2GxV32 z%58pw3`WBnN*OvcQy*Me%VB=od|tZ1>K{{Hsd z8_hu;9`c8U_AWZP*60jxc;Pi2C_Cm{iOe_5>vXRXKeHgd~| zPWC4?`iZF}Zi^v#rM%#n^}WkpltC*a|0$rroV+Xj;9AviwMEC^tXcJQ_miqh1V+qu z4vb=3_m>34QNg5O7GsIr=$l|J_BYH3MI{8*bKRdRt6ft(i&{2;yX-?@EBkOdA}=f* zVR@!uv$?@b*gbWc=P8m(HDGT-&rON$J({9%{$ln?M^y7qGs)ua^H}`P zrR`{&&|gdQk4QTpAKF?Q@vo!si(mFS06%LLPKDjg-*V&3nr&grQLLJb!l=}L;@Vj0 zlAYfgoJ~ER4tfYM7ji{B6*5Z#v-vszZSXNMk}^d;JN+jc5-{lIsjpQBFR_X;hSjQY zY6_FilOyp1Fv?6WlJuj)3lQ57#25M9?V;ENQJytR;vN^P@_kR#edJu>VY`EBt z&o)x&`qZ0_3XfIu?K#14_&FAlaa+AzVuYsZV(y1F0PZTq$;fCe(DSZX0Ue&ksuIgB z1AB6BAR{DJ*YD~dR*r9vU)Z(OFjMaP$b(}9y0Zm>2~POcqou=#qP>Vl6(}}N-D}U9 zy65j%rFs8;-!f3u1SG)(OBkLr{DPx|qDwOO|W#l?ayIlUMJ?ds#j8(h{?Xcy> zm$=n=`w)r8KW7U?t0U9ZW0hMN@D2`LS0&Q`)IdAezx-s*XmQ~g-c_q&+u=wznlHkg zHf9>3J@>UO>iq@wR*_=c8xD%6elP2u*q)LIPuVJ-8743`Q9MP!9FXp2<~=5se9v5k zRZfteM$}y)iw(_0Hor^929iy-WN`Jtpp~t*DymlWQa(jG@h3g_=P6Ht$pvp%CI^S< zKEuT`lU^i5iriiJxM7q#zH_tGO8HWo;}@?1Q;!WpgRqS#AOQ zHNjMJs%k($^?A@8?O16iJ`YI;z(haUxF|F2>sHO3Y~keJ zLbJw}dYtXV_>YyM&x61Z0CYgeZ#};Wa z%>-i%MD|H;N5|NzqpB&VTT=kbmL>om4u{MGU_s>fyu;GSTZXz^Vmj8G{l(weMv7EO zj6@B`nlW#e^YXhX-q_uok?=iv5qpm4hv;q7?Kpw_?H~P-@Y!Z6Dt%Zv(D^;1T z;vIQ39LnLyEYp(c{Au~z2|QtUS$q!fH5Cz|DSy9uc>=o78NxXRI%Mw;1k9(8()Q%PIUhNuE=1aCE3tCwyHM0i+q+69 zuQ7Ltd$*&6_(f|-6-Lfm5cAQ3c|H{#Za4K5D69HlXI#y_;XG4O=1%KSMhNvO5RhpN zS6L#kmr>^{+Mq>0_@CkJM_+veHIg z#qKL3*Q{HV7S0V$TCmC~OpW{OtaSm*+#mrZlvh5<=jEQkcThAHO5W2OQz8!)OOFea zLKB{S*A3zGPLzTz)Q3>7$)>2T=2a6;N1XBP41L%gRj2sART4YJ3ygNQLL%t*YP{C- zvU4yytS^U2)C(CfVz4-d!?qk$?aQ2)MArk#m!=A74J;slXr%s98hJ;~3wZgyW15P` zjlD}p6X~bC%1rhv3%r`O_uRU0#h#H3(fP9vq4=egfuF^rZj9o%&5`(kRErfP-wNJ#!#yrd-i`0O2~#;{-U%&vZcHmBa_~`Lifk7?fb1cH2 zBQ)eEC)G?6rI!j{efzXM8q%Yhs&v8O!5#k$bO80+A&`Mmj{h1rHyDAbChq()RjWMS zH#_CC0b{%48Y#a=O!Wi|#~d3+q|8)^Xh%L2bVEH(iXM&lP5lc{qhsgF?!NSYs8P0t ztj%YQ_<>o+HVx@C&ob_Qs3LN}A{BM)W9~t?Mt@DK=cKcFkOL|jLxslPAp$-<*eiLi zrauNi$is5$U+B1eM@*V*#iL?HNWu}TxtMmxRphxINRMNl3C6&(EA|#(2F#yl6So@m zsDLmm`~Fm4vL*xmqv$Lwf%QWBYJqpKw3s!ccyXK|VPs;=q!?EzQi}FipkG?bO~m-d z#4lK~Dfot3n+^mFQ=H(%(y3@6V~Ow#AmOVcQ!5qkh;kl$OSo1V$|m0JIGp`Vr&*KO zd$}W%KrT(AfDm@r_mIYOf63i%jF1w8~ds6Mtjzg@%#aAMF+io$dnc3 zgU1Ps^7jmiM%2HG=-)KmJ8YKUUwBczkti2v6}eOg>)dgl4A?l~a(^$9UrkHD#ss76 z04V(ew{tyK9|NS#+-hD;_$*S!;HtEZuv67uNzTS#GOQO7)_Li9%}Y$#+&GoIVU}UD+u3t{SJ*?I+oNb}nCwQFsmRYmUKvBXNrT+Sm+k&soNtUb^znf{e zf99N&a0Hehw*WF-j$r$iw`&z92P;1By%Zw{Qxz01>>H z$ax{%R<9}A3y}6yKWO^4&9-^@^uk!$%ZAh2BMpp?zw6%0X$sDWH<{_c8a*$#fjxX% zNlZC67o6eSYT8}NZJj<)9t1TzdD-4Pvep7+#IalWl+~o#{~&Fs*be(ug_(bJ@vaR# zSXBM0^cVk~^BGtZpKB&Jh91y2UXNP)L#|87o7c_E#_@f*l8HKjLm-o~*VA8+AgJ9r@p*WI5*>9;OiVdw-0)mG5C*qP{5kI2k0T&c2ExG6R z0Z#`V2zI@N!y~PVuzd~?hA&SovLCeEV5NlXxZ1POua*1R$vKQ|F!P`G`qs1PlIpxW zstLHRE+_CkA!m^@YJO%DbxxnAEBHfwZ*O*tbt5bf-@z9mT2XdwZ;rJnm3N8GFqJlk zyIpKq>)zLis!0!p4)4-!2&ECJIY4XCPs4vm+dUldz*e~Kgkjr`7PN1AriH8}UKt2a zN)yVo1JEpgIoc~6tM?cxHBYQmEG?Z)kj>GYqW15^O^U%t=PPT{Anv?Mz@ph|rU|}< zhHphx5lC^{)DNIG0NPgdy@|6*u9dM$upy7`Nl)CwfoiDfs6)z^jx_Qq){fX>yZItW z!mCvpY{;Vo9YAY9x^{U;x9cw+cJcWYe12#6TN=!pevx}sRpwjTRV5*Mx3yaW0v^Qh zv@89CHJw_kesR_gn0Vk#}4$9cVK5nPT(R9XbZh;6=K&CBn3Z9ASBE>D>=12!dv&E5vr zc}Z-?(jBw;6(QO!NxQ)_=*O>4f<*MIF6H58qQu?0jl?C5r{g^x9i@hY7uOoT zxmPZg`t(uP6ogvvSexcuSdra8b?q*E<8EF;+o#)MDz`g=GKB01>N_`hN zzUEBkYeJ!V+;)V<_w+p+s5DLVdg$*RIq$`#zEo(+gvvgr@5nR(**H=7CL)*e@O=*U zZY53lWf){-W~Qw?Ku*uoPNBQ$mVQKrGv)e_?3JupC4rwM=pyda_fQt^cS^s~{2>Dl zi|}i!DA#mhQpYtQUwcC_O9*0r%Dd7Vv$}8Db@B4uX`^jIqBK)sY6Yo+JtzJsJ&UxcpI?Ry9IUF?$I8Oz0D2jPPlaMYh*lWLDG{slF z_atSUYq3;S8&o8{Cmek0$c;!s{)t}u=ZzW=l%c3TI1+v(;BfqFS6I+$U|A{%iY0sQ zg_l)^6n0`xTYXB%|IQEK`pDD9!nO=e#%z| zJ~04DWS>svB}U$(0r@Fa3`Ut$yhB*c@5S)ZTlM+jG4_2)ex*Y!_tKdwwCk)ltFKOS zjpZdc0m^I)x39|so{RNtk5*FIB;+4AHu%q#F-Zlj^iZv?i2pv}kEG|yN%xXxgYA1j zPf}n(hYgNR-vQIqiZ!(yVPRa%(NlYX&)mms23uOQYtef5|6%^)v^m48Q`_7TOq0S9 zo$i>z<+Sm+$aA@BGq74*AD}4gM#g7ayNmn({CH1L$x>i@2UT%c*JZmn9bzjvT>w zdjOBI5&FDw!vzX+KY11it4dh~@qJ_Fo$K6JyM_=gH`R;(3orC;HnH+_ zDkgH~y_)xi0oQwXUotRLhd1JikPcGQY!!rCjQKO@!yR*c+B+lhWtrNc{0ac)rdE@o z1Rx{oI}_xe_EFJ)!C?(hNM`h3KiufU4vjCplvlW~#<^47@zqASiFwvvxpl~@M*aUD zz!;({tQqB%0gq~u6PRCOXJM4Dce;%Qxp)61{;%zl^D&r0rTf`JO}oxhMxo`xIdQZKOa9; z7fAgV4jGZAhyUe9!+`)cZi|_Dk-7}d>SU6legvPoeYzH7J=ebgS6S^CjX}xRH7FRR=Qk!eLU3&qJr{7e)tdNxgx;sP}ZwDkAuu=C#t(4f|COg8m{-U4m0%VoY<<>uVyVxC5t z16iwgcbU|kHF8I#stJ2 z6&`xpn>=%Z#umZsb8*^Ex??2{D9F_Q&%s6T3jSA!bHmWkP%${$c!BnA3BvdLYQvpz zFTLzV0*c%-n6*Qqat1xG>1)XmdaD-KQFaH3cwV2HCNJ@Vy={{;uhwBq^V&P;b_-Zy zy&w2&fa?oq+;DrlAfs~WEd04BG_nX*MVUM=vyiE{+O#sUEN-#0a5Jk1HrVmzgH(lY z*Hs@P8rilY`Q2h8QDOeO>49se)Shc6`>c8Ah_v=Ou`1FwDmN00@w3RxDfcGC%WUJ8 z?ugL_dXD6y{psp<%h=Mqc=)aDB@V1OZJmXsSF zU}CQck~9v5d3J0u^R=fUA=eH;bJ43x)LyB%c3hp^d&hML_cf=VBIwwDt9w2Ce+^t@~a@ z@Zu74RKhB3BL?-W{ez6FExT}6_oh#cdD%0L59b(ya=+M_gT&m^;YM5&2avr;+x4$oQD7F~(# zQe9Exy1I#NgDbA6`aj^hFgL4&8+jLMa*0M7VSM*QM(1dhJU``ZtYF$_D3uOf{-Y(9 z`3kjocHOqG^Mz?XD9TyiT9xsZX7y(UuZC=w$6fN?8stbGBNeYojW`Tr!N7kfhuOTE zqta2Y#s1Ugg)@3)5m#b2rVH2$mqNdLtPV?>8J9g^zABPD@Izl*X8U7g36P9orWpj-iEPoF+*WuKiaQb}L~bw>i?GyQG_ zvYTU6)dGI36m{Y~L)%D6N{X1-#JcXyx0iX^3TS zsTZ6ppL03TV+^deni!P6I|I=h3Zq;9(KpuK!#E5q66 z(K2?PpKteSam#tGoo|ovEVKyOw@<x7tg%ljc4tCdCBLJ56{Y~2Wm0pAbc~iJoH&cNzo-hmo?}{bA6Md_ zlgfGSw{3=7^H`WrY`RqSmAJ86Y2Wu}!zEYnuCR2CSf-l+hy6`=9FDgk6`N!@Liz!x{DMphGf%Y2qMI>q^XA++`eoQyc%Hs!Gq5ZO#U*a5WNjb87 z2Rz}xQ~IWdMI_u|tfVp}fz=lj9>!YMTd5~{u&kMjVroFP`*k>`Y3wX??U?ZEG(>&Z zJ=L?-=6>GSP%>ecO>R8~B6}8^u|83$f)z1dTiry%x;~=XA8$z6gedlm)0YYsV{a+a zmrB|VN8+a4s{Z@FE}`z#&CXg(9xS(Vz@Ba5nWsu?!)m4X)Hu8TwS}Iw*c6!6a;4PC zpPUHrZz8!luNHaJ2xBd)fv#1P4pZbaBJDLoe3KD`GF`O_O&o))f`hRGD<2G`Gex;~ zdUw^>@M{r1qiQDrHy<<(#c^J;e!1A4V2k;dV_1Uo0K(vT_s938$!qKwh38}f-h4CZ zzH99<#YfPQIq@9v9v;_$Nd>$g>1o;w@$*KkZ5BVIaW6 zb8gSeUUhRi!@nq)#6r1^|xYpn1 zR3i$4$wP+gg>>UYX*X0+89Cp(!2OO%A6a!Bwv;|C7aH%PQhjCrt8-zUNBSNNi<*VZI%=#l7lvtbbFl6~*G{_Zs#yf}@6GH~TYU=(!fyEdY`I@u5eJIPUZPW_jW`(zB?i%H?C`7HCH@%YCjPRPOjAZz~I`)3Kms7y`lGU0ywJYzb4hy($~$$JjC4CK|Nxx z_%pq>9!WFiO+DN=6Hzg5aCcJqFoEdjFtcHU&Ps*divN{Af%SNp05qYQkW0^K&h)5} ztw$H7r>SDpVG9 zP+Vk}kGvETkeTS+8SXk#w|wHDOD$zOgf;Qjh6Y+NuZsE=i`M?WxOWo^-o`11OW0Z^ z+PL)vv8E}+nqUZbf)i5lw?=k#?PD%VI?fO0XqOs|mAOQ$73+1Sb-xc|H+Hj`M^@X6 zrUd;EPkj!o#xZ=QiR}3iS;qbcNiaIxoQl6s?sj*AT%lB-mUMY~qJm$mOA8mXgx>;$ z=UY2(u0)K->;>#8m7JtwqW?8wfP&QV_*K(g==jNF`@}Qx-Wa~O4_w+_z!cv0ihHab z3&LG~=Kl<-%8w8wCd2cM(PD8-gCUpJog=rBAZg&TehkQ6pGl3A5u<$??pGv%?@iT( z>WrpGtnGJcu`$a|he;A(fEz(Ow|qM#ls@6-(0xU^4s32kqx`@(b#Iq$Z1E_xJ1pv6 z;3UTH6tvuZx!{*a1uIZ|ony%}D!%E>8Ib>KzCCHA+bJ*jMuKjxS`C8FRWHxPYz!D5 zKe;?4WO}S72q`{MU0>?nu`8T}@gqct!;j z)T`vtR;dlygfCxQBQ{cR!Al-EBIwr!0%gfbp2toW+5RB+n!fa(?J$kRJO~alvc}^| zfak3Gt;*=b;6ma`0dm~%);dcFONOHkw%88!gYJ8&v)e#q*1&j2tABr*V99u{gP{wL zAA!9n&$#5p^n=kWSKDTF54|VlU3kn0>=LcFM2JRtPD1daK7MqkH0VAx&$xfhX86Zw zT|W?wbSke9(`%T+>AHEpB$%Xz4yTsukCxo${O?8POd69iD|FCu`D^7}>tSD-hMb2< z&BB?hGdp48U{jX!oC64}bmdX^pUVG}Ri1(eQN>-(`uJNKHc2=b+__@a#%ZJOCFZY)^fyPWCSXPJgO7kYrJzzs_^sVPFLg={ecHa8> zlJ5KklbY?7rC-I>Pj*;MI4%p1In|JWgMc*NbN;NEz^+KznXi>e2U6afF8PG|n8h2X zsU%^#9EP_OL@;yLU3lJ73BMEz0Dj(I@7wP~Vt#RxSu!XD=?D1-0SMY$gBwxm4{|Q$Q7UD+161jKMdmY1M%LvpZmVWyfWF`{wLm zuCd|4Qfm2j3xxIv$c7ehQjZoORmJMwGHjLFsfv!V0){pV?ifGKdovICvtlS{S8Rv%8 zP>b!-%6&>gH8^F9P;BCs?Xrb=K9=u75$(&p)qyG!IpO??{R zQAk&O=JMgEDywG-RKHmvt+iY5K=6>~ub(I0mXK1iMp1mNlRoSS21YrF z{`bFGCBlqfv|rlL03FEgE)VF%E{VH!rnzxmWQtU;0d zqj$eKSg`x%6=8-eeagU9@xDD-;pC@fh!oCST(t~dyZ~4~N_}~}&W4_AY61sTDqZKD)A zCvGz{J$o?O8t#v?i^Hw+OyOBlCKUK=Qh3y6A`qv`8+e_@2lLIK<;yh3$TuhGS^?V` zpD0HD@ve+0k|IQLGeO)vye+f1Rye-m3AX%!MJ@)&YwjM1#dh}D+@nzmY+_Cb^b6?9 zxDR&1(}&o@DvEi&OR$?>&K43ynbHXRQpu^Q9y2_iyU{&zi*D1;wtaJW0;$wqNMVTr z)_#9iM>F4HS3ba%LTlY{sx;2dE@=fqj$hEejn!iFFnnU|0>*Lf9SjO{FW8*ESRdg! zY6vrQ0s~pS5~=v!+usq(C(t(|XJQOm80~(bNpF1a=Gq_Mkh)()9ur+43LgYLFqz^zhZ2?? zQ#IZsemvdY$M6B_;`hs2kZu48Hum7b9IR+v%3GD-N91lpSqmG7@f>c$=f7 z4}{%yluS0V1%g^*=db#?Z_V+MKAsuqkLo&i!5sHoCCr;|i}Zr`>3E1MbJou~`q~v6{q@(CcyeVY5DlskBaYA zXkg6TRt7pEEH3*;*VUc#F?$PacO1rwx^0U`c^T^I6TSkS#|>704OuUoP{HK-8c#v; zMM3v*JJIDUH(I^tMlZ@%e4&CeG!jx$y~P}bpZ29ZI=4J3UNd&#z3%r?R99yqoG@Bx zg>gV%`0W(XT1P;n-rIPMRL<%5zgYnG_03H!#r9vv8r3twTo6rDr$Lnqs zxR7wV{nv)ZXAA?i%8(c6=$Wg!cT?`Hr_P$-=h^j4`5FkIOFz|o$br8+(pd*46PTV} zV3W94?b9_69MG40-*|s|*b4DqINQ;WPvFPz#~XQReI}MsH|5nis$Y!lD^X9j;AhJ1 zAs9b;a%6cpz2xG8Z5;FW@^R3y>2CsA(oT)L8pLm2E+&5c{CjE%PvMgoN?dWsD}%jm zW^G+9L6|7z`)>8Go&~+*QToX5D*8cdZrvN-rsf%y^)1BpcP3kZ;EN0L*A=1f;$5~~ zT(=Ia9$P#L>Wr4;&xiv1Wu&ASf#KcDu7qWNoYsv|-RurJw7Bna_gyhU_vQ@l68jZ&T5`VwS^-shOY>idtC&-s`!TZX`m&CW z=wvfby>u6kggDTdG4Hf)53!Dhok z$A1HEH9@fJV<_SvhAi|6l$$iRCtUELwpFi11-N$X6KlYi6+6xTYr( z_z{}r`;JRWH;J0_f8Nrk`sP3k^x-?`+9gkN5ZI(d?+2D2INfGUYfoWG_D8qitkyQA zj#exD0pTI$ljy-RVu;V2_WPyP%yWlQ$DXCrO6`(n|E;U}kI9i&?;h0hl2~FZ zVN>`i{1YHVu}F-DqHnx|X8ApYu3Vb&<=bEVB>v~KPv2~|etOWzJZfS)$Cy~j>VyP7 ze!lawb91k!#17Si?Whp!qE0KVTv{h>760B_{s#eVyZqDTiJNb@x4_oUe@=Q*7=*k6 z46DbXq7RuNI_4(8@r-oP|H-Dgq)v0@@i>cxcV+!;u0A+r&oLfv$jha1D1AhTn=$So zN0bwcO)T4t&KJ^p&v3%aX`xX`ij}VZ-6Z1WXEc|iE7o)^|NV*|kr5!}iMk(U+dTQ< zvN1|ajq6*MlbLPhQ1is1$x-0!}e0}n9DGkT&FmIWIx34--k;{G} ztpW#5fXRW0lgOJ4|If#3DC&3q^1M!-ErWhu%3>1bH!)G8)bV+YA6qucNLmv;({3WU z*Id`p>&s0fa)o8Wi5czZ|HQ)|J9$yy-k~0J$(!{n(aWU?i2GY1I#q0b7Be^ zoSV%T%|L>@((i7nZa!YmyHvc?Y}J}Pv7ji zXw1|s8yk&ZLX!w8;@VbvEBb=e$~&>aso)i+3hAW1dj3&x)@s6_s8IL0KR;w`ms;zp z2%^&<&-yz}7&(m%Ana{B3#|q>ZPvj4`G46aTu)u~JB--bCwb<}JY9Ne(ZivIL}GnZ z>+VmzSVo8sxMFF>uxdBWcmF@xk>7(~e)|YiOLKQbb~gUhsBs8OlqWu9R7VX+vq z5lex9o7do~*Y>A+*5D6K$Qexk-%56`;Y?bH_)7TC@k*|{5}}Gg5_k5?#{M6^&O559 ze0%$f1r-$)8&aa8fTAE>KoS+C3{_B(j?#tDJA{ZRNN>_hK)RGj3!R{#l+Zf_g7g|f zO9BZA@4>luoco*c{l~>}k;BP3-?sOD_UDPdbmkFj*frn<;WH5x3rO1V( z`(F<@6?c#mv{5wbH8XKYX@1`4mBYN2Sz=fi?e3iY(vf7!5ZXpl9`v_G=xpV_weII$ zAG{uh|L85m?xQsT>nld2>bUXh`E}uNU`)qbQ2fW4--sXiTgq}#w|<8lVLe=&o_dtS zwJl+&WzNOM15@@eH7im8)np zb>^G4@jkW{w%symZWimI7crtCL%-SHmtXi?=G05wGA~1OxL$gP^ZqOiXM9k3zX@a= zhS&9}H}0gym~#3|7$#j#mmfa%;|1Z$0@?2tms{kBArQ&h;r}K_YVn? z4utvtZJ-`$JhZ|ls;dgI21&r(K<@N8^P$ELE@Rdr7T1q|X;DACz5jj7h+}GgHeS-@ z=BCTALAqlZm-DiA;&Ha$UHGmKRO%BRBmdp&npTQPecj4r^9cjOzr#btp zQkZ!)ToC-c>24L!tC@VPRv$GuuO|c8S|{DutYRagTr*m{CewvNGU0BB(>uS+y?Ob4 zsD|-SgsJ0TkTAK~2R~G)WV74pv_Oq+G9mDRV!&FEn~A99@F^03bJ>tZsvHij7~Sgn zV8r^jk@bh{<+F_3bbu9J)CjjqF)z~JJ;o97gCon;qWko*EI$vg_AAs;XJ(+l z7e$KF*X$F2bZ_NoxnMFCwexWzM++|WVH^1HTc0EZnYBCBc%*pXMpS>sm%ASP#HFaI zc*$9YcS4b*oU5h)yUSKD`6}&ebkq=Jd3c@i*Ys65=wt#|@EO!BC`-5~hzmoMRs=Eh zozY+q>8~YiC64sXcH?O*oI{}GLP2y2hi>b{0V&K|ZH&n{Qks9f+WZZBm#2U`p@V6r zXNoeoRP@>Y*DUlnrNBlIp$6PSKH3q+3p>9m@-{)Q+fZlv`g_RvPL z15$5--XPWRK+k@1UvymKkD=t<%iHc|Y(g`xu0UPwd|qPgBWg zTUMI$xaDFKnl@@!h-t;I1w8rS-eiecx!YdT)2HuLSou?cZoKvXT!ubo~1n5ITxnKd5!`)Uj2|GM2Isa7t#ocb0otz zwqK4v{iRPN1;0LAE4o$qVEen+0zAvrQ&rBiCF8z-y-E zIwS7YOudA0(G^_LJL_ST=GTDaPX$sY*wDqA!r>9PAztj;-*$?)gF7IEMNOBgcB_~{ z4smw3KFi8>s$kY%u&_?>o1tTqZa~u@3i4t2T&Wf%fTNXk`@KBZ0yAoS@Y60f%IdaxyBa&@4H3y@D*Ak)X&W=TO|1>P zj*+mKFl>iuc@4KXY{5>;6zPs^FS-8)~zhk%pt0JvD;A-oGnMGcuOb*@o@O-oMGjQ$oi zTio#}#Fy|meq|iUg>KjtT}DD5&WS~J3354wvi95_n$2t?#;W2IFaeC4M`G3(ek};H zhaMh1tTJs;b1!K~QFlPIpE!vZrE_{`om_Jh@R_Mu&58D}d{pi#0J)Hp73@#@(e3>r zOLmhHZed)tQAESR?$0^bWksOOf92*ZN*N$Ewvju+FcT@@MBf+$$Ij^TOSBGH9+#sB?!pY3JZ z8~Vh&z{H&K@Rr~qdHyv%tA8oWA9)our$k_kuph-J2 zRPn<4t!lyK`=SbCAn&tcojtJDHe~`SEELC8! z2gcy$tE}tlFq2AX_W0@9khWic{j>Z*eu*^n&UD(1Ln`?e59bb-v@3-Y5F6~ke;d{= z8+I=AOi^b>At!!?JeL&i!-t?#+m>=>CLy3j=C8(Uav^+s#E-mk>c(I?_!6?<>5iB$ z{EZi%)3rB;3*)E4hrEA;^(iJBmJN>Q<%#xlnwYu97n8vX{n%n%o4KsYZP2fbMt#cZ zt*J7u>AeGa+W1cSlc!LDW>x369hux|j?}USM;kTruKw6AJf3EIW13Elr-e0F!Y}=G zm^va7{yKy$VKt5Ih32!_Z>ODYCVf>Bwg8zA@-Zk->ebFzU-o2FnwwYFj7@c0Z?)*l zSRfD2zj3uMtx@$_7ak|vN8Jx^FqI5mP&8l#snxs3xyw+VG_i=%iHg^)cRmDjX2);( zJ~15j5JsMiF2lt*$J=OO%nFy5(c_nOXPN(cVgHl{)UnE~;*iY6KeB4czK&1} z)KsfZb`)Qt1Th3FzY!d9@`aQ^j<0%{+SY;eYgBpb4Am{KQmQ|uva=JwdQSc3W`G`s zYtO9dvYq_w0?a&mPVPClGDk-#p{9Q7(d5y!CiSmZQ84iy9y|%Z<`HmZQS)f=Dp4_T zuT{jNsfVR6*sw~1xS*eO0sLr|rS)~Sc;V6@W&d1ZVxl?Pdsg!~q~dpt0+kG6HaXi# zBj1@dj~=>UTe<;=7mAxe!ucS{lLG?9TaLHFG{y(Bm0eSP@T;ST>ZUOIKs`Iw(caN3 zu&oJ{8?{0iI;c`WL2sw@FsuKI^m=dVD-^yCNn9dSGo6JDdYWz9D@-;$Iu9v)>NTXq zo4ItsbCD7=yjqG->^YET4fY41Y@MFQ*FQqu`iXt-Z1P^}oABTvV}F-#+Anb5cKyyD z5#~ExC`=zt`s!6pSmb1pyGKM=jxJbk!?$}+%09~Yz9Xs&G|Fg}u+iNcWTL)t3rpPc z{huN6*N|;F`#IofRA+Yy1~BNun!X}Tf8+O#Y^&YnavgYUOL{I zoAx9j;#<0`^yUHK1|kzUT)59){+9dTxR?n1cNv=&2JX(6U;T5XF3kioH_2~Kzfyw* zd`}eJZ!YOAqYt4fbHsKZlgxp9^eNu;`_^EVp@f3WD{yRZE4l7`VTAfoeuS|0VK2-w z|C*-%^G&X4*S~$I>Er46abYrOV(Z1~0f)&J)~TWwNWGN4>`t`|Km@vP$vo*zy{q5x zv&3QHz%7x_VQeFDS-T?w9QuWzQp-irsY_^Y9kXBC(BHdUeGW1Wxuq#i&)=A3g_Pp0 zH!Nzp`CY@_H$O29+Pbzz6{!np766W{Z}ycxw8(b8>>W?B@H>vkk?$rllYQc|c3+VT z@x)%z?-CY9`xBc5x7nq?-J6<1B||wwVn=3H{O95q^(WtZG(>-A26cYhWCj#&LJz;( z%CHuK-My9#dJFiiR~KeIU)tzvllUhX)OJv{NhkstoyE@ zIO~1($U)|>oqYlNhP07fC|aCv{$C1-f2L-Q_MbQ~z-^Fk-!M{&gz80-wqEVt>?P~n z<+}KxtbxLHCP&Tm_}Us(=>{>ZOCkB89zmdM!J`HO4$69aK z5iV)t(DCU5fm@W}4Ar|0*%#VlR9fZd9t<0DegNcZPbl&h8LC$(NSOSR-|xm*JcAe= zpR7~2=6FH;T3umh;}x{J;dbZ$ThUCu07g$3g zteNP2az;}z9P8^?CR3Sy(n$UQ?}*Jvjdluv1qTEaDAhS?4<_AYrDDm-FU*{oTToK&x~kzpEpDSH~7J8%Ekq&0mTy z#(aL2=$8UEs50OLiK`jF;YGK!%d}5&3@LU<6_Jw|6=0C?69=?-M+FE-dRC?AYUilF%)kMKD_VZ@LdgZ8vD$PjP+DrfvvEY`f5nmiJs@3*crAC7_)LqxFlVFq`OZB( z+e-tIb({u}8pLIv(^$xw=lX>a^P14vPA=2iaX04gXEn&RqGYAP27c-sfyM9)&#X`h zb%KS}IJ}+hD`ESD6xC$dLt@)+ZYJe|d24D4e!7^2u^EV-XBKsvnwfXSie4}m9wgO4 zsbT=6Jk!Zy`~ivMu6lx~6}N4jsDTZ7s&kzZSLC^Q{4haW!KQ{T$?Dw~;f^O~8PavQ zm6NQo&z?PN?u1iVDgm|0hEDkq+iktlX3j|f10teWW<&FEckjzvUmB--mowAeY;;5* zaBk8^lgDCA4*UuR{`^Vgf zaIuqDgLFps?%7(I5qf@SpCF=s%{#^AV5s-&1!pm~z`^Qbv(cazl&?sG692UULPr!3 zb&m`V!Y3|QP66>|swcMjiYj1(n}VRkTaOnhsY+L5C*8}>7Ih~?J)MoQ2%3(ZqO@=s z&$b3SKXq6uqD|*K(Dx-ei*yOIfX}I1<$#n{Cpo(bSoY^X9IzSThO=+`Bw5KFmL`2~ z5*p2Sq_2Y47Xm}p0g$aJCELmbU5mw>;~wqu$^0{9z$H-qj>K7h*TGpM>y^TN0T|uM~1`eKK5X83izDl~nK2?^@cN zk(IRUvG|&ySZp_Obpcmfo#eJt1aN#kJ()i5sa|fC=#S0Do2T#_<1X@Kr+9s24e3!% zfv;Vc=m_SH7lI}LJuy!XA~Gcb*n9<}or*fnaz<{YMYOL54V_K@X$>HAk zq6cYfSZ$qOX)tr{oWon~xu?Rdi<-hCpK4k0&hu&han~mHm0SHSTlSw(r~Z}U(qSk2 zZ_P(IG$RVFr~LSVHi;%IR@P_ux|$#(dzW)QxO5o^5{m0G!)_1J-| zBn%}cJzAQcmCtH%7q7jwmk%lj>v3m~uf7RRu4^2ydN>yc3jJWt-5v{M{$}#v7x@P1 z3n!?wQtu71O8hthqYZ&68l<4Qifg27GueqWb7g=dU26IGhHG#VfA-kc8~s5JHNj54 zRt)}q>>rL+!YXd_B9`lCw>J#wug-|@$@)^sxZT$^o9lci8+taP1+?pwtupc?ZXcQ- zy=%)nQU%D}Tiemw1uAm$Z_2-i#U|R&L#zQo`}a^!&6O&uf&19#F=ZZ=BMZD~PxA(w zXFs)*h_>FYc{PG7w@a+c?rm=h&pxv!kDvf{(dUiZx~SF>=cQ#Ul_M|_*FsnUmDYb7 z9rYMla}#Kx`Ou9Fi$;t&mE;=|3dr9RZCl64V*;J%)kq-1IIR)~bgFT4wq75OQ z7HncRr5nnF8BnZ?n4<7X``VY>e1Mg!7yFpo9o2BH@_b-k@6sw2=!6^0@6oHipps}v zr=0JW4I8Lk?ZJG{ZnZIA@3SN&%oDp5S0E2j3&?q0f$HxxCLf}pbdamQLm6Q*#%uzMBF}t-d0B|QoXWWW2`a<^Y&*=`{M5Jpbl9eb-ne9|G zb&rRpE2agM#3~{Rq01yyF)ldg4(_PNW1K9?di(~Ydh$-?Y~KTv*F-mLMmb8o=k$XD z-JvixSGPw}gVSv|PqGM?9k{q@Yko?tdBSY-TP(6lh!;Zs8novo(87c8dKn8NNbRZt zG%%Ye;lkbd_ZO3Gwuu6n&Uw#JHbtxt(#zfXgjW*oRxOzCS}n!gHnhPmg2)r&*=n}i zxbj`ZheX-lAc2rGV{=U#vn_j4IvhLXL8!FH+a!-x#V;N!-_R*;t%VzjhP1Dt7kjRC z3c#I%YSu@r93~FUVa+^3A=Cx6W#Lzw&m1L%a^tvbXGR!=t1Pvg%jVZ0+nexwEs*e; zKeDX{W#u(gl1V7N<*?0oi%17a4l}tv<%H?6VpWW72*N^MgEnanDNA=0iFX_$ijN#@ zx2($x{n~?Xk6TM~TIkU>YfmZ2YkepjC@-(X;a0zYebEYuef-2`v$Mw(W6k!r?Ad?9 zg!>Cj7H2<;tvR@UZycnZRw&!dD{wW2+NS68zn|yf^i92LN`Sr(8)W$-4d_8G#spIk zA5}KvCAoDYR<`s#wGe8U)m(29@uydG1kznP zBsi)22hG8et;`?f-o{zQG$No~+&H>o{r(=YO`&oE4mV?g$aC6PY%UEBqIz{b7N8X( zY3Z7L!l1jUXjlQ9Ld3K59b%FZ2xS!<-dH%4yFb)*lfl)k8h2Lid~6WN(jE_ z{Xt)=vs?=aQ@&~*SX-O2VTVmJKjUC(YU&~zs+%>_38uE;0t+4IRA*71C9(zQZ|U(4 z8aS45WR`UV15)(h$)4#^Fm?GhBgfsgP&%+IaPMxOxA|xE5q{jqX-!tTM0xF{>p=XX zRkiep=SMdW=`Tb^Ppaq%lcj0z7pknxKvy)`cTnmQiSW73bNE0U818I$8C|(}Bz~8S znMMpIv)|IKwa2_@3mY#+r|n?CcDn>9U3*A;_G zb{WIzYaG24JKF7H3-ne}^oZ|ww!X9!8_jS>Ef;|Vb)E`Ed7tFhsd;{wL=a%3VPQ`b zPjl&_tc!Lxhea4cPN`4C3QE((>4fh~?Fu1WCL>aWAwW~JK7?MbTr8*-VU4f^6v|3j zH>>qnj@!J#4zQieYzns;sd7$qS{Rk+$p?+KD$>0pg8Roaq&8O*r|`$`H>&UzOP?G$qDu(%J}CU> zG?|%(_!2x6zo~Ov$|$GQvUenSAf5}<7I*p{dVWtyE1+*5uRmwF>)pz|^=diz(EmLR zURIA};8r%t_L`bmISJWD@o*9pCuYdP=!Ti~RXIRka6`zTJNN=;=G=tbs735aLkNuP zEv67x=1O$2x#?T%&XxPHB7aG2v#;8bZK12Ma&%{_+F|jFCw6Yo;-%bfh==P7JGTSX zv8v>iDZx z8M>W`+hT@WJKG<*q(^U$js~L8-{c}ItG4uPw`b&F^Eseo;D~hI_F4L9K_aVV*=5n2 z@(AV)i)W)0~pwe9NSZPAcqutOG7F-*x3m2yR!6HQk&V62YV18b&QZk(;*P0Hs zJHL&g>z0@m>}<}VkHl>JN@)K#GWkQdo_2m9C^9QdV3D=TgXMK8&vNU+WW)riZ!d`c z5z;5A5BWdn>)90;K_*$ofc$hzc63yo=Xic**R%qBdta3U=YeRBbfOFi? zAZ{~$l+?!PG6qKz1A@1@6||?q_66GhJZC=>PB2GF6f%SLZ;uOhZgl64==qWg5{3tX zNu?Z9K;*n{dqHFs!ED|UsW@B7ClKcG)O*(-GLq4@njTtO-rr;1X(2SReZim@y1C7t zV6-&`Eyt#NFUIdS-$qxf%*IdG1E718%k)1$gu2On}&_qXLA{liu5=tQU(OjDBjaps zRm2-cHSq9uV!U*dXN(5KQCCu5jq0a#>;z{GqP8rtuzWZCOR)=HXS+MhHhfSntZ2}X zD!=1VK@L#ja7Rz=y+=i+HlT8m)XxgOLQL5QUJ(9t zq8n0bT)lL98PWhGcs!!6bTc25W-9mI@|7vSQ0U6)TJ9~=9yU}SbZ@)2cX|Z~JIN~^ z7|!o>nq+H`IO6&R`g(Nz1fb-=sIt7JQxM-K-MA|)za=?eP)`?Lm#FRpOhH-)k+eW}F;%8&+|ecwAF@VrRzKBo!&Xhq3P(DcenQ2ur!(0 z&W-E1H&vQHC>vI%Mlc{fvrHHY2v$D^bw$*Aj^O9#Kk0hI6QvjGU{r-{RSvvWt-%4t zx|Fo)y2btQ?*!!nx{B409&)|<bZ6fvS|5>5ob>DxXWbI?B z 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 hf&4^_lCM+i<>1 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 literal 0 HcmV?d00001 diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/assets/readmeImages/core-concepts.png b/app/multi-tenant/central-space/cloud-cap-samples-java/assets/readmeImages/core-concepts.png new file mode 100644 index 0000000000000000000000000000000000000000..286989fc3f3ed9a9f9a1587e0f9d6b82f0a7d76e GIT binary patch literal 116291 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 literal 0 HcmV?d00001 diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/books.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/db/books.cds new file mode 100644 index 000000000..486e83282 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/books.cds @@ -0,0 +1,96 @@ +namespace my.bookshop; + +using { + Currency, + sap, + managed, + cuid +} from '@sap/cds/common'; +using my.bookshop.Reviews from './reviews'; +using my.bookshop.TechnicalBooleanFlag from './common'; + +@fiori.draft.enabled +entity Books : cuid, managed { + title : localized String(111); + descr : localized String(1111); + author : Association to Authors; + genre : Association to Genres; + stock : Integer; + price : Decimal(9, 2); + currency : Currency; + rating : Decimal(2, 1); + reviews : Association to many Reviews + on reviews.book = $self; + isReviewable : TechnicalBooleanFlag not null default true; + cHapters : Composition of many Chapters on cHapters.book = $self; + pages : Composition of many Pages on pages.book = $self; + virtual isAttachmentsUploadable : Boolean; + virtual isReferencesUploadable : Boolean; +} + +entity Authors : cuid, managed { + @assert.format : '^\p{Lu}.*' // assert that name starts with a capital letter + name : String(111); + dateOfBirth : Date; + dateOfDeath : Date; + placeOfBirth : String; + placeOfDeath : String; + books : Association to many Books + on books.author = $self; +} + +// annotations for Data Privacy +annotate Authors with +@PersonalData : { DataSubjectRole : 'Author', EntitySemantics : 'DataSubject' } +{ + ID @PersonalData.FieldSemantics : 'DataSubjectID'; + name @PersonalData.IsPotentiallySensitive; +} + +/** + * 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; +} + +/** Adding {Notebooks,Writers} for user service */ +entity Notebooks : managed, cuid { + @mandatory title : localized String(111); + descr : localized String(1111); + @mandatory writer : Association to Writers; + stock : Integer; + price : Decimal; + currency : Currency; + image : LargeBinary @Core.MediaType: 'image/png'; + virtual isAttachmentsUploadable : Boolean; +} + +entity Writers : managed, cuid { + @mandatory name : String(111); + dateOfBirth : Date; + dateOfDeath : Date; + placeOfBirth : String; + placeOfDeath : String; + notebooks : Association to many Notebooks + on notebooks.writer = $self; +} + +entity Chapters : cuid, managed { + book : Association to Books; + title : String @title: 'Chapter Title'; + description : String; + url : String; + chapterType : String @title: 'Chapter Type'; +} + +entity Pages : cuid, managed { + book : Association to Books; + title : String @title: 'Page Title'; + description : String; + url : String; + pageType : String @title: 'Page Type'; +} \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/common.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/db/common.cds new file mode 100644 index 000000000..a1c0cd805 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/common.cds @@ -0,0 +1,10 @@ +namespace my.bookshop; + +//////////////////////////////////////////////////////////////////////////// +// +// Commmon Types +// +type TechnicalBooleanFlag : Boolean @( + UI.Hidden, + Core.Computed +); diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/API_BUSINESS_PARTNER-A_BusinessPartnerAddress.csv b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/API_BUSINESS_PARTNER-A_BusinessPartnerAddress.csv new file mode 100644 index 000000000..0e0ab64c8 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/API_BUSINESS_PARTNER-A_BusinessPartnerAddress.csv @@ -0,0 +1,6 @@ +AddressID;BusinessPartner;Country;CityName;PostalCode;StreetName;HouseNumber +100;10401010;DE;Walldorf;68199;Dietmar-Hopp-Allee;16 +200;10401010;DE;St.Leon-Rot;68789;SAP-Allee;29 +300;10401010;DE;Potsdam;14469;Konrad-Zuse-Ring;10 +400;1000020;US;Newtown Square;19073;West Chester Pike;3999 +500;1000020;US;Palo Alto;94304;Hillview Avenue;3410 diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/Statuses.csv b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/Statuses.csv new file mode 100644 index 000000000..2cea5d749 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/Statuses.csv @@ -0,0 +1,6 @@ +code;text +Unscanned;Unscanned Attachment +Scanning;Scanning Attachment +Clean;Clean Attachment +Infected;Infected Attachment +Failed;Scanning Failed \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/Statuses_text.csv b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/Statuses_text.csv new file mode 100644 index 000000000..f205875c3 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/Statuses_text.csv @@ -0,0 +1,6 @@ +code;locale;text +Unscanned;en;Unscanned Attachment +Scanning;en;Scanning Attachment +Clean;en;Clean Attachment +Infected;en;Infected Attachment +Failed;en;Scanning Failed \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/WDIRICodeList.csv b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/WDIRICodeList.csv new file mode 100644 index 000000000..22ebc12db --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/WDIRICodeList.csv @@ -0,0 +1,4 @@ +code;name +1;1 +2;2 +3;3 \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/WDIRSCodeList.csv b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/WDIRSCodeList.csv new file mode 100644 index 000000000..d2bbc28bf --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/WDIRSCodeList.csv @@ -0,0 +1,4 @@ +code;name +A;Promotions type A +B;Promotions type B +C;Promotions type C \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Authors.csv b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Authors.csv new file mode 100644 index 000000000..84d7eb449 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Authors.csv @@ -0,0 +1,10 @@ +ID;NAME;DATEOFBIRTH;PLACEOFBIRTH;DATEOFDEATH;PLACEOFDEATH +335c7bcd-b826-4f14-a788-e0bf6738617a;Emily Brontë;1818-07-30;Thornton, Yorkshire;1848-12-19;Haworth, Yorkshire +e3da2c2e-72ee-45d5-8def-52964c7b252a;Charlote Brontë;1818-04-21;Thornton, Yorkshire;1855-03-31;Haworth, Yorkshire +e7643aae-2d2f-4656-bb2d-1328ad3c8045;Edgar Allen Poe;1809-01-19;Boston, Massachusetts;1849-10-07;Baltimore, Maryland +3c081d9d-abda-4da9-8b6a-4f4555bb26bc;Richard Carpenter;1929-08-14;King’s Lynn, Norfolk;2012-02-26;Hertfordshire, England +b834ddb0-613a-4edf-8d47-7d80989e1325;Jane Austen;1775-12-16;Steventon, United Kingdom;1817-07-18;Winchester, United Kingdom +a57f75fa-2bda-47b5-ab4d-b644570f29cd;F. Scott Fitzgerald;1896-09-24;Saint Paul, Minnesota;1940-12-21;Los Angeles, California +b22f5293-7eea-49bb-9ee7-17c5de81f1df;Harper Lee;1926-04-28;Monroeville, Alabama;2016-02-19;Monroeville, Alabama +1d2ec887-cbf1-491e-943e-33a2b4f39a6f;Gabriel García Márquez;1927-03-06;Aracataca, Columbia;2014-04-17;Mexico City, Mexico +c0526b1a-9a75-4a43-9133-163325cbbd2b;Truman Capote;1924-09-30;New Orleans, Louisiana;1984-08-25;Los Angeles, California diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Books.csv b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Books.csv new file mode 100644 index 000000000..dd4baa1a0 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Books.csv @@ -0,0 +1,6 @@ +ID;TITLE;DESCR;AUTHOR_ID;STOCK;PRICE;CURRENCY_CODE;GENRE_ID;RATING;ISBN +f846b0b9-01d4-4f6d-82a4-d79204f62278;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.";335c7bcd-b826-4f14-a788-e0bf6738617a;12;11.11;GBP;11;4.5;979-8698267973 +9b084139-0b1e-43b6-b12a-7b3669d75f02;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.";e3da2c2e-72ee-45d5-8def-52964c7b252a;11;12.34;GBP;11;3.0;979-8598716472 +51061ce3-ddde-4d70-a2dc-6314afbcc73e;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.";e7643aae-2d2f-4656-bb2d-1328ad3c8045;333;13.13;USD;16;2.5;978-1092909747 +aebdfc8a-0dfa-4468-bd36-48aabd65e663;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.";e7643aae-2d2f-4656-bb2d-1328ad3c8045;555;14;USD;16;1.0;979-8669820985 +4a519e61-3c3a-4bd9-ab12-d7e0c5329933;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.;3c081d9d-abda-4da9-8b6a-4f4555bb26bc;22;15;EUR;13;4.0;978-3473523023 diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Books.texts.csv b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Books.texts.csv new file mode 100644 index 000000000..b25a0a125 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Books.texts.csv @@ -0,0 +1,5 @@ +ID_TEXTS;ID;locale;title;descr +f846b0b9-01d4-4f6d-82a4-d79204f62278;f846b0b9-01d4-4f6d-82a4-d79204f62278;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. +f846b0b9-01d4-4f6d-82a4-d79204f62279;f846b0b9-01d4-4f6d-82a4-d79204f62278;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. +f846b0b9-01d4-4f6d-82a4-d79204f62280;9b084139-0b1e-43b6-b12a-7b3669d75f02;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 +f846b0b9-01d4-4f6d-82a4-d79204f62281;aebdfc8a-0dfa-4468-bd36-48aabd65e663;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. diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Genres.csv b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Genres.csv new file mode 100644 index 000000000..88e73bddb --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Genres.csv @@ -0,0 +1,16 @@ +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;21;Autobiography +23;20;Essay +24;20;Speech \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Notes.csv b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Notes.csv new file mode 100644 index 000000000..c5a069795 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Notes.csv @@ -0,0 +1,4 @@ +ID,note,address_businessPartner,address_ID +83e2643b-aecc-47d3-9f85-a8ba14eff07d,Packages can be dropped off at the reception,10401010,100 +880147b0-8d2d-4ef8-bb52-ae5ae6002fc5,Don't deliver packages after 5pm,10401010,100 +5efc842c-c70d-4ee2-af1d-81c7d257aff7,Ring at building 8,1000020,500 diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-OrderItems.csv b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-OrderItems.csv new file mode 100644 index 000000000..b13f3b2eb --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-OrderItems.csv @@ -0,0 +1,4 @@ +ID;QUANTITY;PARENT_ID;BOOK_ID;AMOUNT +58040e66-1dcd-4ffb-ab10-fdce32028b79;1;7e2f2640-6866-4dcf-8f4d-3027aa831cad;f846b0b9-01d4-4f6d-82a4-d79204f62278;11.11 +64e718c9-ff99-47f1-8ca3-950c850777d4;1;7e2f2640-6866-4dcf-8f4d-3027aa831cad;4a519e61-3c3a-4bd9-ab12-d7e0c5329933;15 +e9641166-e050-4261-bfee-d1e797e6cb7f;2;64e718c9-ff99-47f1-8ca3-950c850777d4;aebdfc8a-0dfa-4468-bd36-48aabd65e663;28 \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Orders.csv b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Orders.csv new file mode 100644 index 000000000..3439fcfb3 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Orders.csv @@ -0,0 +1,3 @@ +ID;CREATEDBY;ORDERNO;CURRENCY_CODE +7e2f2640-6866-4dcf-8f4d-3027aa831cad;john.doe@test.com;1;EUR +64e718c9-ff99-47f1-8ca3-950c850777d4;jane.doe@test.com;2;EUR diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Reviews.csv b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Reviews.csv new file mode 100644 index 000000000..679dcdd54 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/my.bookshop-Reviews.csv @@ -0,0 +1,25 @@ +MODIFIEDAT;CREATEDAT;BOOK_ID;RATING;TEXT;TITLE;CREATEDBY;ID +2019-11-26T03:29:46.178Z;2019-11-26T03:29:46.178Z;f846b0b9-01d4-4f6d-82a4-d79204f62278;1;So expensive. ...you can buy the same product for less money :( It broke after 1 day. Poor Quality. Called customer service..no answer. I'd expect a little more durability. I'm a dummy for not throwing all in the trash.;Just crazy! Don't buy it, PLEASE!;roman.zamora@test.sap.com;8089768a-14ae-3cd0-807e-c77ceab8f91e +2019-03-18T17:51:25.128Z;2019-03-18T17:51:25.128Z;f846b0b9-01d4-4f6d-82a4-d79204f62278;3;Lower quality than expected. Would buy a better quality next time. Works fine, but it is fragile.... For a straight up purchase not a bad choice. Does not look the same as the picture provided...which was disappointing, but ok. Packaging is not the same as getting it from the website. Everything's working like it should. Quite ok -- nothing extraordinary, though.;Exactly what I expected;minnie.biddle@test.sap.com;8098ea0a-e4b9-3265-9a21-95758a1e49e0 +2019-09-10T11:57:14.747Z;2019-09-10T11:57:14.747Z;f846b0b9-01d4-4f6d-82a4-d79204f62278;5;Can't relate to the bad reviews I saw, I definitely like it. This product is incredible awesome! Perfect for my needs. Wow, wow, wow. Speachless! This product has changed my life.;Highly recommended!;howard.pitts@test.sap.com;80a31701-4c04-3107-a50e-7a2ead69e421 +2018-09-20T06:33:01.940Z;2018-09-20T06:33:01.940Z;f846b0b9-01d4-4f6d-82a4-d79204f62278;5;Overall I am extremely pleased with it.;Great Product;frank.birdwell@test.sap.com;80b4a989-ca48-3b62-bc10-3545412152f8 +2019-11-15T19:56:56.923Z;2019-11-15T19:56:56.923Z;f846b0b9-01d4-4f6d-82a4-d79204f62278;1;Why is this even available here? We were able to return it for a full refund. I have to say that I'm quite disappointed. I'm a dummy for not throwing all in the trash. Too expensive for what I received. Not recommending to anyone. Very cheap. I don't recommend and will not purchase this brand again. I'm actually really surprised by the positive reviews, which I relied on when ordering.;Don't consider...;tyler.liu@test.sap.com;80d832ed-54c7-3296-bcb9-8a377af1639e +2019-03-06T12:37:07.494Z;2019-03-06T12:37:07.494Z;9b084139-0b1e-43b6-b12a-7b3669d75f02;1;Reading these reviews, I really had to wonder if I had bought the same product. Didn't work, that is why I cannot recommend this product. We were able to return it for a full refund. I'm a dummy for not throwing all in the trash. Not recommending to anyone. Very cheap. No instructions included for use or installation. The Worst I have ever seen!;Overrated and overpriced;latonya.nash@test.sap.com;80db5094-4fab-34cb-882a-84514eedd58f +2020-03-19T09:23:29.028Z;2020-03-19T09:23:29.028Z;9b084139-0b1e-43b6-b12a-7b3669d75f02;2;Works as advertised. Not good, not bad. Works fine, but it is fragile.... I would recommend this item to anyone who wants it. Not bad for the price I suppose. Does not look the same as the picture provided...which was disappointing, but ok. Material seems a bit cheaper than I had expected. It's okay. Nothing special to mention on this one.;Cheaply made, not so cheap price.;phillip.smart@test.sap.com;80db9105-b865-312e-acf8-ec42d9bff2cf +2019-05-04T13:59:10.057Z;2019-05-04T13:59:10.057Z;9b084139-0b1e-43b6-b12a-7b3669d75f02;5;Can't relate to the bad reviews I saw, I definitely like it. I do really love this product and think it's a good buy. I love it so much. It looks beautiful and modern. Never saw a quality like that before. Sleek product! A great purchase, thank you! I was surprised how nice this product really looks. Overall I am extremely pleased with it.;Perfect choice!;dona.lawrence@test.sap.com;814f6f8a-94a1-3f05-87f6-74c186536efe +2019-11-24T10:16:53.266Z;2019-11-24T10:16:53.266Z;9b084139-0b1e-43b6-b12a-7b3669d75f02;5;Excellent engineering and the feeling of a very high quality product. I love it so much. I do really love this product and think it's a good buy. Unique and beautiful. Excellent quality. Great service. I would buy this product again, if I ever need too, big smile. Not expensive for the quality. Why didn't I buy these sooner? Such a cool Design! That was a good choice, would definitely pick it again.;Nice Product!;dustin.park@test.sap.com;81718a76-0ecd-3aa1-97b8-c04df011aa16 +2019-06-13T18:24:50.994Z;2019-06-13T18:24:50.994Z;9b084139-0b1e-43b6-b12a-7b3669d75f02;1;Too expensive for what I received. Not recommending to anyone. Very cheap. This is a role model for annoying a customer.;Not Suggested;phillip.brewer@test.sap.com;8186e063-0e1c-3310-9313-451bcef5f1f6 +2018-08-11T10:49:14.710Z;2018-08-11T10:49:14.710Z;51061ce3-ddde-4d70-a2dc-6314afbcc73e;5;Fantastic, I'm totally blown away. After using that product my business skyrocketed! Why didn't I buy these sooner? Such a cool Design! Everyone in my big family has one now - both adults, four teen and one middle schooler. It's convienent for me.;Love this brand!;rita.spencer@test.sap.com;819b6821-3482-3fd5-963b-ea9361d60986 +2020-11-07T07:45:10.731Z;2020-11-07T07:45:10.731Z;51061ce3-ddde-4d70-a2dc-6314afbcc73e;2;Haven't seen good alternatives, so I picked this one. Would buy a better quality next time. It does it's job. For a straight up purchase not a bad choice. I would recommend this item to anyone who wants it. Quite ok -- nothing extraordinary, though.;Well...;kelly.zheng@test.sap.com;819da75a-2d12-3167-86bf-8987f82d7c12 +2020-01-12T22:01:00.127Z;2020-01-12T22:01:00.127Z;51061ce3-ddde-4d70-a2dc-6314afbcc73e;1;It is fatally flawed and should be avoided. Nice looking product, but never worked well. I'm a dummy for not throwing all in the trash.;It's just ok;jay.townsend@test.sap.com;81aaf7f7-e6cf-3650-9b9f-660588e2ca38 +2020-06-20T05:07:17.150Z;2020-06-20T05:07:17.150Z;51061ce3-ddde-4d70-a2dc-6314afbcc73e;5;Does what it should, so definitely deserves a good rating. Definitely worth the investment. Unique and beautiful. Excellent quality. Great service. A great purchase, thank you! They hold up and last a very long time. Great quality and exactly what was described. I looked around quite a bit before deciding to try this and it fulfills all that I wanted. That was a good choice, would definitely pick it again.;Great Product;lawrence.harp@test.sap.com;81d030d3-90ba-3bd1-bef8-0347d990bcdf +2018-09-25T13:54:52.786Z;2018-09-25T13:54:52.786Z;51061ce3-ddde-4d70-a2dc-6314afbcc73e;1;I should have read the reviews that warned about how short, or small, this product is. I'd expect a little more durability. Lower quality than expected. I don't recommend and will not purchase this brand again. I'm actually really surprised by the positive reviews, which I relied on when ordering. Didn't receive what the picture looked like. This is a role model for annoying a customer.;Don't buy;eddie.hart@test.sap.com;81d1152c-acbb-3fa1-abbc-66397150f2eb +2018-09-19T17:30:31.927Z;2018-09-19T17:30:31.927Z;aebdfc8a-0dfa-4468-bd36-48aabd65e663;2;Go for it, not really bad at all. Works as advertised. I would recommend this item to anyone who wants it. It serves the intended purpose.;Ok, but has a few issues;stephen.bratten@test.sap.com;81ea3917-8374-38b2-897d-000ced6c10db +2020-09-07T16:28:48.032Z;2020-09-07T16:28:48.032Z;aebdfc8a-0dfa-4468-bd36-48aabd65e663;1;Called customer service..no answer. Horrible! Unsatisfied in every way! No instructions included for use or installation.;Please don't;karrie.lawrence@test.sap.com;81f015f4-59c2-33ef-8d2e-d77692e7ce8e +2018-05-21T22:58:40.021Z;2018-05-21T22:58:40.021Z;aebdfc8a-0dfa-4468-bd36-48aabd65e663;1;So expensive. ...you can buy the same product for less money :( The description is wrong. I sent it back. Looks better than it works. Horrible! Unsatisfied in every way! Lower quality than expected. This is a role model for annoying a customer.;Useless;abbie.banes@test.sap.com;81fa4a9e-4071-3c74-a07e-8bae2ca88168 +2018-12-01T14:29:03.340Z;2018-12-01T14:29:03.340Z;aebdfc8a-0dfa-4468-bd36-48aabd65e663;5;I love it so much. Unique and beautiful. Excellent quality. Great service. I was surprised how nice this product really looks.;You need this!;marshall.alexander@test.sap.com;82011880-e1aa-3019-8899-dee0647d2be8 +2020-03-07T06:46:29.181Z;2020-03-07T06:46:29.181Z;aebdfc8a-0dfa-4468-bd36-48aabd65e663;1;Didn't work, that is why I cannot recommend this product. I'd expect a little more durability.;I don't recommend and will not purchase this brand again;kay.steinberg@test.sap.com;8216ead4-3292-38e6-a53f-ecf0555bc9f2 +2018-08-22T00:11:59.829Z;2018-08-22T00:11:59.829Z;4a519e61-3c3a-4bd9-ab12-d7e0c5329933;5;Definitely worth the investment. Does what it should, so definitely deserves a good rating. The good things are still available, this is the proof! This is great! Unique and beautiful. Excellent quality. Great service. They hold up and last a very long time. It's convienent for me. That was a good choice, would definitely pick it again.;Good value;isabelle.wong@test.sap.com;823e509b-8565-3a12-8cbb-2af042e5e509 +2018-08-19T16:11:20.884Z;2018-08-19T16:11:20.884Z;4a519e61-3c3a-4bd9-ab12-d7e0c5329933;1;Nice looking product, but never worked well. I'd expect a little more durability. Lower quality than expected.;Don't buy;tracy.zhang@test.sap.com;827ebe9b-b6d0-36ea-a3dc-3ca50bc4809b +2020-06-28T10:00:33.344Z;2020-06-28T10:00:33.344Z;4a519e61-3c3a-4bd9-ab12-d7e0c5329933;2;I didn't bother to return it but will not be purchasing this again. If you're looking for something durable and heavy-duty I would not recommend this one. It does it's job. Works as advertised. Works fine, but it is fragile.... Does not look the same as the picture provided...which was disappointing, but ok. Quite ok -- nothing extraordinary, though.;Just regular general purpose;rodney.franklin@test.sap.com;82813174-e1f2-31f5-8b8c-1d044857979d +2020-11-07T03:11:14.727Z;2020-11-07T03:11:14.727Z;4a519e61-3c3a-4bd9-ab12-d7e0c5329933;5;Does what it should, so definitely deserves a good rating. Fantastic, I'm totally blown away. This is great! They hold up and last a very long time. Not expensive for the quality. Why didn't I buy these sooner? Such a cool Design! This product is incredible awesome! It's convienent for me. Wow, wow, wow. Speachless!;Good Value - Good Quality;phillip.smart@test.sap.com;8298deea-443c-372e-bba3-628b003f6845 \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/sap.attachments-UploadScanStates.csv b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/sap.attachments-UploadScanStates.csv new file mode 100644 index 000000000..8432b60db --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/sap.attachments-UploadScanStates.csv @@ -0,0 +1,6 @@ +code;name;criticality +uploading;Uploading;5 +Success;Success;3 +Failed;Scan failed;2 +VirusDetected;Virus Detected;1 +VirusScanInprogress;Virus Scan In Progress(refresh page);5 \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/sap.common-Currencies.csv b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/sap.common-Currencies.csv new file mode 100644 index 000000000..d68d1028a --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/sap.common-Currencies.csv @@ -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 Britian Pound +ILS;₪;Shekel;Israeli New Shekel \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/sap.common-Currencies.texts.csv b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/sap.common-Currencies.texts.csv new file mode 100644 index 000000000..b192b4c1a --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/sap.common-Currencies.texts.csv @@ -0,0 +1,13 @@ +CODE;LOCALE;NAME;DESCR +EUR;de;Euro;European Euro +USD;de;US-Dollar;United States Dollar +CAD;de;Kanadischer Dollar;Kanadischer Dollar +AUD;de;Australischer Dollar;Australischer Dollar +GBP;de;Pfund;Britische Pfund +ILS;de;Schekel;Israelische Schekel +EUR;fr;euro;de la Zone euro +USD;fr;dollar;dollar des États-Unis +CAD;fr;dollar canadien;dollar canadien +AUD;fr;dollar australien;dollar australien +GBP;fr;livre sterling;pound sterling +ILS;fr;Shekel;shekel israelien \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/sap.common-Languages.csv b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/sap.common-Languages.csv new file mode 100644 index 000000000..c935d462f --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/sap.common-Languages.csv @@ -0,0 +1,7 @@ +name;descr;code +Spanish;Spanish;es +English;English;en +French;French;fr +German;German;de +Italian;Italian;it +Russian;Russian;ru diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/sap.common-Languages.texts.csv b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/sap.common-Languages.texts.csv new file mode 100644 index 000000000..5949b2f6a --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/data/sap.common-Languages.texts.csv @@ -0,0 +1,19 @@ +name;descr;code;locale +Spanish;Spanish;es;en +English;English;en;en +French;French;fr;en +German;German;de;en +Italian;Italian;it;en +Russian;Russian;ru;en +espagnol;espagnol;es;fr +anglais;anglais;en;fr +français;français;fr;fr +allemand;allemand;de;fr +italien;italien;it;fr +russe;russe;ru;fr +Spanisch;Spanisch;es;de +Englisch;Englisch;en;de +Französisch;Französisch;fr;de +Deutsch;Deutsch;de;de +Italienisch;Italienisch;it;de +Russisch;Russisch;ru;de diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/index.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/db/index.cds new file mode 100644 index 000000000..8d94253a2 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/index.cds @@ -0,0 +1,6 @@ +using from './books'; +using from './orders'; +using from './reviews'; +using from './notes'; +using from './common'; +using from '@sap/cds/srv/outbox'; diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/notes.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/db/notes.cds new file mode 100644 index 000000000..47d3687ca --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/notes.cds @@ -0,0 +1,7 @@ +namespace my.bookshop; + +using { cuid } from '@sap/cds/common'; + +entity Notes: cuid { + note: String; +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/orders.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/db/orders.cds new file mode 100644 index 000000000..e09ef50b8 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/orders.cds @@ -0,0 +1,25 @@ +namespace my.bookshop; + +using { + Currency, + User, + managed, + cuid +} from '@sap/cds/common'; +using my.bookshop.Books from './books'; + +entity Orders : cuid, managed { + OrderNo : String @title : '{i18n>OrderNumber}' @mandatory; //> readable key + Items : Composition of many OrderItems + on Items.parent = $self; + buyer : User; + total : Decimal(9, 2)@readonly; + currency : Currency; +} + +entity OrderItems : cuid { + parent : Association to Orders; + book : Association to Books @mandatory @assert.target; + quantity : Integer; + amount : Decimal(9, 2); +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/package-lock.json b/app/multi-tenant/central-space/cloud-cap-samples-java/db/package-lock.json new file mode 100644 index 000000000..6477c690e --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/package-lock.json @@ -0,0 +1,179 @@ +{ + "name": "deploy", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "deploy", + "dependencies": { + "@sap/hdi-deploy": "4.8.2" + }, + "engines": { + "node": "^18" + } + }, + "node_modules/@sap/hdi-deploy": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/@sap/hdi-deploy/-/hdi-deploy-4.8.2.tgz", + "integrity": "sha512-LDouJ0i6oTLOrYWLeyp4PKF5cIBeKnn70gksdlg/bq3q5G/UNgGmqL62TEHbXehbeJfc0DKfEp9yal4IFD5k1Q==", + "hasShrinkwrap": true, + "dependencies": { + "@sap/hana-client": "2.18.24", + "@sap/hdi": "4.5.1", + "@sap/xsenv": "3.4.0", + "async": "3.2.3", + "dotenv": "10.0.0", + "handlebars": "4.7.7", + "hdb": "0.19.3", + "micromatch": "4.0.4" + }, + "engines": { + "node": "^12.0.0 || ^14.0.0 || ^16.0.0 || ^18.0.0 || ^20.0.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/hana-client": { + "version": "2.18.24", + "dependencies": { + "debug": "3.1.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/hana-client/node_modules/debug": { + "version": "3.1.0", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/hana-client/node_modules/ms": { + "version": "2.0.0" + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/hdi": { + "version": "4.5.1", + "dependencies": { + "async": "3.2.3" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv": { + "version": "3.4.0", + "dependencies": { + "debug": "4.3.3", + "node-cache": "^5.1.0", + "verror": "1.10.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/assert-plus": { + "version": "1.0.0" + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/clone": { + "version": "2.1.2" + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/core-util-is": { + "version": "1.0.2" + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/debug": { + "version": "4.3.3", + "dependencies": { + "ms": "2.1.2" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/extsprintf": { + "version": "1.4.1" + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/ms": { + "version": "2.1.2" + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/node-cache": { + "version": "5.1.2", + "dependencies": { + "clone": "2.x" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/verror": { + "version": "1.10.0", + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/async": { + "version": "3.2.3" + }, + "node_modules/@sap/hdi-deploy/node_modules/braces": { + "version": "3.0.2", + "dependencies": { + "fill-range": "^7.0.1" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/dotenv": { + "version": "10.0.0" + }, + "node_modules/@sap/hdi-deploy/node_modules/fill-range": { + "version": "7.0.1", + "dependencies": { + "to-regex-range": "^5.0.1" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/handlebars": { + "version": "4.7.7", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/hdb": { + "version": "0.19.3", + "dependencies": { + "iconv-lite": "^0.4.18" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/iconv-lite": { + "version": "0.4.24", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/is-number": { + "version": "7.0.0" + }, + "node_modules/@sap/hdi-deploy/node_modules/micromatch": { + "version": "4.0.4", + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/minimist": { + "version": "1.2.8" + }, + "node_modules/@sap/hdi-deploy/node_modules/neo-async": { + "version": "2.6.2" + }, + "node_modules/@sap/hdi-deploy/node_modules/picomatch": { + "version": "2.3.1" + }, + "node_modules/@sap/hdi-deploy/node_modules/safer-buffer": { + "version": "2.1.2" + }, + "node_modules/@sap/hdi-deploy/node_modules/source-map": { + "version": "0.6.1" + }, + "node_modules/@sap/hdi-deploy/node_modules/to-regex-range": { + "version": "5.0.1", + "dependencies": { + "is-number": "^7.0.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/uglify-js": { + "version": "3.17.4", + "optional": true + }, + "node_modules/@sap/hdi-deploy/node_modules/wordwrap": { + "version": "1.0.0" + } + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/package.json b/app/multi-tenant/central-space/cloud-cap-samples-java/db/package.json new file mode 100644 index 000000000..491f70822 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/package.json @@ -0,0 +1,13 @@ +{ + "name": "deploy", + "dependencies": { + "@sap/hdi-deploy": "4.8.2" + }, + "engines": { + "node": "^18" + }, + "scripts": { + "start": "node node_modules/@sap/hdi-deploy/deploy.js", + "build": "npm i && npx cds build .. --for hana --production" + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/pom.xml b/app/multi-tenant/central-space/cloud-cap-samples-java/db/pom.xml new file mode 100644 index 000000000..79515c4d5 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + + bookshop-parent + my + ${revision} + + + db + + + + + com.sap.cds + sdm + 1.8.1-SNAPSHOT + + + + + + + com.sap.cds + cds-maven-plugin + ${cds.services.version} + + + cds.clean + + clean + + + + cds.resolve + + resolve + + + + + + + + diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/repository.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/db/repository.cds new file mode 100644 index 000000000..ae103dc8d --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/repository.cds @@ -0,0 +1,11 @@ +namespace my.bookshop; + +using { + cuid +} from '@sap/cds/common'; + +entity Repository : cuid { + repositoryId : localized String(111); + externalId : localized String(1111); + name : localized String(1111); +} \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/db/reviews.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/db/reviews.cds new file mode 100644 index 000000000..7015fbf62 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/db/reviews.cds @@ -0,0 +1,31 @@ +namespace my.bookshop; + +using { + User, + managed, + cuid +} from '@sap/cds/common'; +using my.bookshop.Books from './books'; + +entity Reviews : cuid, managed { + @cds.odata.ValueList + book : Association to Books; + rating : Rating; + title : String(111); + text : String(1111); +} + +// input validation +annotate Reviews with { + title @mandatory; + rating @assert.range; + book @mandatory @assert.target; +} + +type Rating : Integer enum { + Best = 5; + Good = 4; + Avg = 3; + Poor = 2; + Worst = 1; +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/fts/isbn/schema.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/fts/isbn/schema.cds new file mode 100644 index 000000000..c26572691 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/fts/isbn/schema.cds @@ -0,0 +1,31 @@ +using {CatalogService} from '../../app/browse/fiori-service'; +using {my.bookshop as my} from '../../db/index'; + + +// domain model + +extend my.Books with { + isbn : String(40) @cds.collate: false; +} + +// Feature 'isbn' will display ISBN in table and on object page +annotate CatalogService.Books with @(UI: { + FieldGroup #General: {Data: [ + ...up to + {Value: title}, + { + Value: isbn, + Label: '{i18n>ISBN}' + }, + ... + ]}, + LineItem: [ + ...up to + {Value: title}, + { + Value: isbn, + Label: '{i18n>ISBN}' + }, + ... + ] +}); diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/integration-tests/pom.xml b/app/multi-tenant/central-space/cloud-cap-samples-java/integration-tests/pom.xml new file mode 100644 index 000000000..0d3f7bc73 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/integration-tests/pom.xml @@ -0,0 +1,135 @@ + + 4.0.0 + + + my + bookshop-parent + ${revision} + + + bookshop-integration-tests + + bookshop-integration-tests + + + ../mtx/sidecar + node + + + + + my + bookshop + ${revision} + + + ch.qos.logback + logback-classic + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.security + spring-security-test + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.5 + + false + + + + + org.graalvm.buildtools + native-maven-plugin + + true + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + 3.2.5 + + + + integration-test + verify + + + + + + + com.sap.cds + cds-maven-plugin + ${cds.services.version} + + + cds.install-node + + install-node + + + ${cdsdk-global} + + + + + install-sidecar + + npm + + pre-integration-test + + install --no-save + ${skipTests} + ${sidecar.dir} + + + + + + + org.codehaus.mojo + exec-maven-plugin + 3.2.0 + + + pre-integration-test + start-sidecar + + exec + + + + + ${cds.node.executable} + ${skipTests} + ${sidecar.dir} + true + true + node_modules/@sap/cds/bin/cds-serve.js + + + + + diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/integration-tests/src/test/java/my/bookshop/it/FeatureTogglesIT.java b/app/multi-tenant/central-space/cloud-cap-samples-java/integration-tests/src/test/java/my/bookshop/it/FeatureTogglesIT.java new file mode 100644 index 000000000..816337c4b --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/integration-tests/src/test/java/my/bookshop/it/FeatureTogglesIT.java @@ -0,0 +1,58 @@ +package my.bookshop.it; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; + +// This test case is executable only when MTX sidecar is running. +@ActiveProfiles({"default", "ft"}) +@AutoConfigureMockMvc +@SpringBootTest +class FeatureTogglesIT { + + private static final String ENDPOINT = "/api/browse/Books(aebdfc8a-0dfa-4468-bd36-48aabd65e663)"; + + @Autowired + private MockMvc client; + + @Test + @WithMockUser("authenticated") // This user has all feature toggles disabled + void withoutToggles_basicModelVisible() throws Exception { + // Elements are not visible and not changed by the event handler + client.perform(get(ENDPOINT)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.isbn").doesNotExist()) + .andExpect(jsonPath("$.title").value(containsString("11%"))); + } + + @Test + @WithMockUser("admin") // This user has all feature toggles enabled + void togglesOn_extensionsAndChangesAreVisible() throws Exception { + // Elements are visible and changed by the event handler + client.perform(get(ENDPOINT)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.isbn").value("979-8669820985")) + .andExpect(jsonPath("$.title").value(containsString("14%"))); + } + + @Test + @WithMockUser("user") // This user has only 'isbn' toggle enabled + void toggleIsbnOn_extensionsAndChangesAreVisible() throws Exception { + // Elements are visible + client.perform(get(ENDPOINT)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.isbn").value("979-8669820985")) + .andExpect(jsonPath("$.title").value(containsString("11%"))); + } + +} + diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/mta-single-tenant.yaml b/app/multi-tenant/central-space/cloud-cap-samples-java/mta-single-tenant.yaml new file mode 100644 index 000000000..2ee6770a1 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/mta-single-tenant.yaml @@ -0,0 +1,95 @@ +_schema-version: '2.1' +ID: bookshop +version: 1.0.0 +description: "Bookshop CAP Java Project with UI" +parameters: + enable-parallel-deployments: true +modules: +# --------------------- SERVER MODULE ------------------------ + - name: bookshop-srv +# ------------------------------------------------------------ + type: java + path: srv + parameters: + memory: 1024M + disk-quota: 512M + buildpack: sap_java_buildpack_jakarta + properties: + SPRING_PROFILES_ACTIVE: cloud,sandbox + JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jre.SAPMachineJRE']" + JBP_CONFIG_SAP_MACHINE_JRE: '{ version: 21.+ }' + build-parameters: + builder: custom + commands: + - mvn clean package -DskipTests=true + build-result: target/*-exec.jar + requires: + - name: bookshop-hdi-container + - name: bookshop-uaa-rashminew + - name: cf-logging + provides: + - name: srv-api + properties: + srv-url: '${default-url}' +# --------------------- DB MODULE --------------------------- + - name: bookshop-db +# ----------------------------------------------------------- + type: hdb + path: db + parameters: + buildpack: nodejs_buildpack + build-parameters: + builder: custom + commands: + - npm run build + requires: + - name: bookshop-srv + requires: + - name: bookshop-hdi-container +# --------------------- APPROUTER MODULE --------------------- + - name: bookshop-app +# ------------------------------------------------------------ + type: approuter.nodejs + path: app + parameters: + memory: 256M + disk-quota: 512M + requires: + - name: srv-api + group: destinations + properties: + name: backend + url: ~{srv-url} + forwardAuthToken: true + strictSSL: true + - name: bookshop-uaa-rashminew + provides: + - name: app-api + properties: + app-url: '${default-url}' +# --------------------- RESOURCES --------------------- +resources: +# ----------------------------------------------------- + - name: bookshop-uaa-rashminew + type: org.cloudfoundry.managed-service + parameters: + service: xsuaa + service-plan: application + path: ./xs-security.json + config: # override xsappname as it needs to be unique + xsappname: bookshopnew-${org}-${space} + oauth2-configuration: + redirect-uris: + - ~{app-api/app-url}/** + requires: + - name: app-api + - name: bookshop-hdi-container + type: org.cloudfoundry.managed-service + parameters: + service: hana + service-plan: hdi-shared + - name: cf-logging + type: org.cloudfoundry.managed-service + parameters: + service: application-logs + service-plan: lite diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/mtx/sidecar/package.json b/app/multi-tenant/central-space/cloud-cap-samples-java/mtx/sidecar/package.json new file mode 100644 index 000000000..e59e3dce9 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/mtx/sidecar/package.json @@ -0,0 +1,25 @@ +{ + "dependencies": { + "@cap-js/hana": "^2.1.1", + "@sap/cds": ">=9.8.0", + "@sap/cds-mtxs": "^3", + "@sap/xssec": "^4.2.7", + "express": "^4" + }, + "devDependencies": { + "sqlite3": "^5" + }, + "engines": { + "node": "^20" + }, + "cds": { + "profiles": ["mtx-sidecar", "java"], + "[development]": { + "requires": { "auth": "dummy" } + } + }, + "scripts": { + "start": "cds-serve", + "build": "cds build ../.. --for mtx-sidecar --production && cd gen && npm install" + } +} \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/package.json b/app/multi-tenant/central-space/cloud-cap-samples-java/package.json new file mode 100644 index 000000000..83094ad6f --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/package.json @@ -0,0 +1,13 @@ +{ + "name": "bookshop-java", + "version": "1.0.0", + "description": "Bookshop using CAP Java NG", + "license": "Apache License Version 2.0", + "repository": "https://github.com/SAP-samples/cloud-cap-samples-java.git", + "dependencies": { + "@cap-js/hana": "^2.1.2", + "@sap/cds": "^9.8.0", + "@sap/cds-dk": "^9.8.0", + "@sap/cds-mtxs": "^3" + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/pom.xml b/app/multi-tenant/central-space/cloud-cap-samples-java/pom.xml new file mode 100644 index 000000000..125460c56 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/pom.xml @@ -0,0 +1,171 @@ + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.2.6 + + + + my + bookshop-parent + ${revision} + pom + + bookshop parent + + + + 1.0.0-SNAPSHOT + + + 21 + 4.3.0 + 5.12.0 + 3.5.0 + 3.8.3 + 9.8.0 + + + + srv + integration-tests + + + + + + + com.sap.cds + cds-services-bom + ${cds.services.version} + pom + import + + + + + + com.sap.cloud.sdk + sdk-modules-bom + ${cloud.sdk.version} + pom + import + + + + + com.sap.cloud.security + java-bom + ${xsuaa.version} + pom + import + + + + + com.sap.cloud.servicesdk.xbem + emjapi-extension-sap-cp-jms + 4.0.0 + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.12.1 + + ${jdk.version} + UTF-8 + + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.5 + + true + + + + + org.apache.maven.plugins + maven-failsafe-plugin + 3.2.5 + + + + + org.codehaus.mojo + flatten-maven-plugin + 1.6.0 + + true + resolveCiFriendliesOnly + + + + flatten + process-resources + + flatten + + + + flatten.clean + clean + + clean + + + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.4.1 + + + Project Structure Checks + + enforce + + + + + 3.5 + + + ${jdk.version} + + + + true + + + + + + + diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/requests.http b/app/multi-tenant/central-space/cloud-cap-samples-java/requests.http new file mode 100644 index 000000000..c8c0e0192 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/requests.http @@ -0,0 +1,16 @@ +### Trigger BusinessPartner.Changed event through S/4 mock + +PATCH http://localhost:8080/api/API_BUSINESS_PARTNER/A_BusinessPartnerAddress(BusinessPartner='10401010',AddressID='200') +Content-Type: application/json +Authorization: Basic authenticated: + +{"HouseNumber": "30"} + +### Subscribe t1 tenant, in local-mtxs + +POST http://localhost:4005/-/cds/deployment/subscribe HTTP/1.1 +Content-Type: application/json + +{ + "tenant": "t1" +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/scripts/create-container-registry-secret.sh b/app/multi-tenant/central-space/cloud-cap-samples-java/scripts/create-container-registry-secret.sh new file mode 100755 index 000000000..e18abeafb --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/scripts/create-container-registry-secret.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +read -p "Docker Server: " DOCKER_SERVER + +read -p "User ($USER): " DOCKER_USER +if [ "$DOCKER_USER" == "" ]; then + DOCKER_USER="$USER" +fi + +if [ "$EMAIL" == "" ]; then + read -p "EMail: " DOCKER_EMAIL +else + read -p "EMail ($EMAIL): " DOCKER_EMAIL + if [ "$DOCKER_EMAIL" == "" ]; then + DOCKER_EMAIL="$EMAIL" + fi +fi + +read -sp "API Key: " API_KEY + +echo +echo + +kubectl create secret docker-registry container-registry \ + "--docker-server=$DOCKER_SERVER" \ + "--docker-username=$DOCKER_USER" \ + "--docker-email=$DOCKER_EMAIL" \ + "--docker-password=$API_KEY" diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/scripts/create-db-secret.sh b/app/multi-tenant/central-space/cloud-cap-samples-java/scripts/create-db-secret.sh new file mode 100755 index 000000000..9282a2098 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/scripts/create-db-secret.sh @@ -0,0 +1,78 @@ +#!/bin/bash + +set -e +cd "$(dirname "$(dirname "$0")")" + +npm install --no-save yaml + +function value() { + node ./scripts/value.js "$1" +} + +NAME="$1" +if [ "$NAME" == "" ]; then + NAME="$(value srv.bindings.db.fromSecret)" + if [ "$NAME" == "" -o "$NAME" == "" ]; then + echo >&2 "[ERROR] Please either specify the name for the DB secret or maintain it in the Helm chart" + exit 1 + fi +fi + +SECRET_HEADER="$(cat </dev/null >/dev/null service $NAME || cf create-service hana hdi-shared $NAME +while true; do + STATUS="$(cf 2>/dev/null service $NAME | grep status: | head -n 1)" + echo $STATUS + if [[ "$STATUS" = *succeeded* ]]; then + break + fi + sleep 1 +done + +cf create-service-key $NAME $NAME-key + +node "$(dirname "$0")/format-kyma-secret.js" -- "$(echo "$SECRET_HEADER")" "$(cf service-key $NAME $NAME-key)" | kubectl apply -f - +echo +echo "HANA DB Kubernetes secret '$NAME' created." +echo +echo "You can view it using:" +echo +echo "kubectl get secret $NAME -o yaml" +exit 0 \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/scripts/create-sm-secret.sh b/app/multi-tenant/central-space/cloud-cap-samples-java/scripts/create-sm-secret.sh new file mode 100755 index 000000000..aecc9ada3 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/scripts/create-sm-secret.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +set -e +cd "$(dirname "$(dirname "$0")")" + +npm install --no-save yaml + +function value() { + node ./scripts/value.js "$1" +} + +NAME="$1" +if [ "$NAME" == "" ]; then + if [ ! -f "chart/values.yaml" ]; then + echo >&2 "[ERROR] Please either specify the name for the service manager secret or maintain it in the Helm chart" + exit 1 + fi + NAME="$(value .srv.bindings.db.fromSecret)" + if [ "$NAME" == "" -o "$NAME" == "" ]; then + echo >&2 "[ERROR] Please either specify the name for the service manager secret or maintain it in the Helm chart" + exit 1 + fi +fi + +SECRET_HEADER="$(cat </dev/null >/dev/null service $NAME || cf create-service service-manager container $NAME +while true; do + STATUS="$(cf 2>/dev/null service $NAME | grep status: | head -n 1)" + echo $STATUS + if [[ "$STATUS" = *succeeded* ]]; then + break + fi + sleep 1 +done + +cf create-service-key $NAME $NAME-key + +node "$(dirname "$0")/format-kyma-secret.js" -- "$(echo "$SECRET_HEADER")" "$(cf service-key $NAME $NAME-key)" | kubectl apply -f - +echo +echo "Service Manager container secret '$NAME' created." +echo +echo "You can view it using:" +echo +echo "kubectl get secret $NAME -o yaml" +exit 0 \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/scripts/format-kyma-secret.js b/app/multi-tenant/central-space/cloud-cap-samples-java/scripts/format-kyma-secret.js new file mode 100644 index 000000000..eccc78a6b --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/scripts/format-kyma-secret.js @@ -0,0 +1,9 @@ +const key=JSON.parse(process.argv[4].replace(/^.*/, "")); +const credentials=key.credentials /* new cfcli? */ || key; +console.log(process.argv[3]); +console.log(Object.keys(credentials).map(k => { + if (credentials[k].match(/\n/s)) + return (` ${k}: |\n${credentials[k]}`).replace(/\n/gs,"\n ") + else + return ` ${k}: "${credentials[k]}"` +}).join("\n")) \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/scripts/value.js b/app/multi-tenant/central-space/cloud-cap-samples-java/scripts/value.js new file mode 100755 index 000000000..91c9ed3eb --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/scripts/value.js @@ -0,0 +1,38 @@ +#!/usr/bin/env node + +const yaml = require('yaml'); +const fs = require('fs'); + +const path = process.argv[2]; +if (!path) { + console.error('missing path'); + process.exit(1); +} + +const segments = path.split('.'); + +function printProperty(file) { + let valuesYaml; + try { + valuesYaml = fs.readFileSync(file, 'utf-8'); + } catch(error) { + return false; + } + const values = yaml.parse(valuesYaml); + + let o = values; + for (let segment of segments) { + o = o[segment]; + if (typeof o === "undefined" || o === null) return false; + } + + if (typeof o === "object") { + console.log(JSON.stringify(o)); + } else { + console.log(o); + } + + return true; +} + +printProperty('.values.yaml') || printProperty('values.yaml') || printProperty('chart/values.yaml') || process.exit(1); \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/admin-service.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/admin-service.cds new file mode 100644 index 000000000..defae7be8 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/admin-service.cds @@ -0,0 +1,376 @@ +using {sap.common.Languages as CommonLanguages} from '@sap/cds/common'; +using {my.bookshop as my} from '../db/index'; +using {sap.changelog as changelog} from 'com.sap.cds/change-tracking'; + +extend my.Orders with changelog.changeTracked; + +@path : 'admin' +service AdminService @(requires: [ + 'admin', + 'system-user' +]) { + entity Books as projection on my.Books excluding { reviews } actions { + action addToOrder(order_ID : UUID, quantity : Integer) returns Orders; + } + + entity Chapters as projection on my.Chapters; + entity Pages as projection on my.Pages; + + // Define a return type for the action result + type MoveAttachmentsResult { + failedObjectIds : array of String; + } + + entity Books.attachments as projection on my.Books.attachments + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self,up__ID:String,objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + } + annotate AdminService.Books.attachments with @( + Capabilities: {InsertRestrictions: {Insertable: up_.isAttachmentsUploadable}} + ); + + entity Books.references as projection on my.Books.references + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self,up__ID:String,objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + } + annotate AdminService.Books.references with @( + Capabilities: {InsertRestrictions: {Insertable: up_.isReferencesUploadable}} + ); + + entity Books.footnotes as projection on my.Books.footnotes + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self,up__ID:String,objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + } + + entity Pages.attachments as projection on my.Pages.attachments + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + entity Pages.references as projection on my.Pages.references + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + // Chapters projections + entity Chapters.attachments as projection on my.Chapters.attachments + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + entity Chapters.references as projection on my.Chapters.references + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + entity Chapters.footnotes as projection on my.Chapters.footnotes + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + // Side effects on parent entities: structural changes (add/delete) on attachment + // navigation collections trigger a re-read of the uploadable flag on the parent. + annotate AdminService.Books with @( + Common.SideEffects #sdmAttachmentsUploadable: { + SourceEntities: ['attachments'], + TargetProperties: ['isAttachmentsUploadable'] + }, + Common.SideEffects #sdmReferencesUploadable: { + SourceEntities: ['references'], + TargetProperties: ['isReferencesUploadable'] + } + ); + + // Pages footnotes projection + entity Pages.footnotes as projection on my.Pages.footnotes + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + entity Authors as projection on my.Authors; + entity Orders as select from my.Orders; + + @cds.persistence.skip + entity Upload @odata.singleton { + csv : LargeBinary @Core.MediaType : 'text/csv'; + } +} + +// Deep Search Items +annotate AdminService.Orders with @cds.search : { + OrderNo, + Items +}; + +annotate AdminService.OrderItems with @cds.search : {book}; + +annotate AdminService.Books with @cds.search : { + descr, + title +}; + +// Enable Fiori Draft for Orders +annotate AdminService.Orders with @odata.draft.enabled; +annotate AdminService.Books with @odata.draft.enabled; + +// workaround to enable the value help for languages +// Necessary because auto exposure is currently not working +// for if Languages is only referenced by the generated +// _texts table +extend service AdminService with { + entity Languages as projection on CommonLanguages; +} + +// Change-track orders and items +annotate AdminService.Orders { + OrderNo @changelog; +}; + +annotate AdminService.OrderItems { + quantity @changelog; + book @changelog: [ + book.title, + book.isbn + ] +}; + +// Assign identifiers to the tracked entities +annotate AdminService.Orders with @changelog: [OrderNo]; +annotate AdminService.OrderItems with @changelog: [ + parent.OrderNo, + book.title, + ]; diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/attachment-extension.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/attachment-extension.cds new file mode 100644 index 000000000..a3dd9c79c --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/attachment-extension.cds @@ -0,0 +1,155 @@ +using my.bookshop as my from '../db/books'; +using {sap.attachments.Attachments, sap.attachments.StatusCode} from`com.sap.cds/sdm`; +using { sap.common.CodeList } from '@sap/cds/common'; + +extend entity my.Books with { + attachments : Composition of many Attachments @SDM.Attachments:{maxCount: 4, maxCountError:'Only 4 attachments allowed.'}; + references : Composition of many Attachments @SDM.Attachments:{maxCount: 5, maxCountError:'Only 5 attachments allowed.'}; + footnotes : Composition of many Attachments; +} +extend entity my.Notebooks with { + attachments : Composition of many Attachments @SDM.Attachments:{maxCount: 4, maxCountError:'Only 4 attachments allowed.'}; +} +extend entity my.Chapters with { + attachments: Composition of many Attachments; + references: Composition of many Attachments; + footnotes: Composition of many Attachments; +} + +extend entity my.Pages with { + attachments: Composition of many Attachments; + references: Composition of many Attachments; + footnotes: Composition of many Attachments; +} + +entity Statuses @cds.autoexpose @readonly { + key code : StatusCode; + text : localized String(255); +} + +extend Attachments with { + statusText : Association to Statuses on statusText.code = $self.status; + customProperty1 : WDIRS_CodeList_TYPE + @SDM.Attachments.AdditionalProperty: { + name: 'Working:DocumentInfoRecordString' + } + @(title: 'DocumentInfoRecordString'); + customProperty2 : Integer + @SDM.Attachments.AdditionalProperty: { + name: 'Working:DocumentInfoRecordInt' + }; + customProperty3 : String + @SDM.Attachments.AdditionalProperty: { + name: 'abc:myId1' + } + @(title: 'id1'); + customProperty4 : String + @SDM.Attachments.AdditionalProperty: { + name: 'abc:myId2' + } + @(title: 'id2'); + customProperty5 : DateTime + @SDM.Attachments.AdditionalProperty: { + name: 'Working:DocumentInfoRecordDate' + } + @(title: 'DocumentInfoRecordDate'); + customProperty6 : Boolean + @SDM.Attachments.AdditionalProperty: { + name: 'Working:DocumentInfoRecordBoolean' + } + @(title: 'DocumentInfoRecordBoolean'); +} + +entity WDIRSCodeList : CodeList { + key code : String(30) @Common.Text : name @Common.TextArrangement: #TextFirst; +}; + +type WDIRS_CodeList_TYPE : Association to one WDIRSCodeList; + +annotate my.Books.attachments with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: {entity:'Statuses'} + ); +} + +annotate my.Books.references with { + content @Validation.Maximum : '30MB'; + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate my.Chapters.attachments with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate my.Chapters.references with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate my.Pages.attachments with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate my.Pages.references with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate my.Chapters.footnotes with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate my.Pages.footnotes with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/cat-service.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/cat-service.cds new file mode 100644 index 000000000..4402c589c --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/cat-service.cds @@ -0,0 +1,34 @@ +using {my.bookshop as my} from '../db/books'; + +@path : 'browse' +service CatalogService @(requires: ['any', 'system-user']) { + @readonly + entity Books as projection on my.Books excluding { + createdBy, + modifiedBy + } actions { + action addReview(rating : Integer, title : String, text : String) returns Reviews; + }; + + @readonly + entity Authors as projection on my.Authors; + + @readonly + entity Reviews as projection on my.Reviews; + + action submitOrder(book : Books : ID, quantity : Integer) returns { + stock : Integer + }; + + // access control restrictions + annotate Reviews with @restrict : [ + { + grant : 'READ', + to : 'any' + }, + { + grant : 'CREATE', + to : 'authenticated-user' + } + ]; +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/external.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/external.cds new file mode 100644 index 000000000..a64baa80e --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/external.cds @@ -0,0 +1,40 @@ +using { API_BUSINESS_PARTNER as external } from './external/API_BUSINESS_PARTNER'; + +/** + * Tailor the imported API to our needs... + */ +extend service external with { + + /** + * Add asynchronous eventing API + */ + @topic: 'sap.s4.beh.businesspartner.v1.BusinessPartner.Changed.v1' + event BusinessPartner.Changed { + BusinessPartner: String; + } + +} + +/** + * Simplified view on external addresses, which in addition acts as a table to store replicated external address data. + */ +@cds.persistence:{table,skip:false} //> create a table with the view's inferred signature +@cds.autoexpose //> auto-expose in services as targets for ValueHelps and joins +entity my.bookshop.Addresses as projection on external.A_BusinessPartnerAddress { + key AddressID as ID, + key BusinessPartner as businessPartner, + @readonly Country as country, + @readonly CityName as city, + @readonly PostalCode as postalCode, + @readonly StreetName as street, + @readonly HouseNumber as houseNumber, + false as tombstone: Boolean +} + +/* + * Extend Orders with references to replicated external Addresses + */ +using { my.bookshop.Orders } from '../db/index'; +extend Orders with { + shippingAddress : Association to my.bookshop.Addresses; +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/external/API_BUSINESS_PARTNER.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/external/API_BUSINESS_PARTNER.cds new file mode 100644 index 000000000..72c3173a0 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/external/API_BUSINESS_PARTNER.cds @@ -0,0 +1,3977 @@ +/* checksum : 33c2afcba69718abba5b5d612738f7cd */ +@cds.external : true +@m.IsDefaultEntityContainer : 'true' +@sap.message.scope.supported : 'true' +@sap.supported.formats : 'atom json xlsx' +service API_BUSINESS_PARTNER {}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Email Address' +entity API_BUSINESS_PARTNER.A_AddressEmailAddress { + /** + * Internal key for identifying a Business Address Services address. + * + * For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Address Number' + key AddressID : String(10) not null; + /** + * Internal key for identifying a person in Business Address Services. + * + * For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Person number' + key Person : String(10) not null; + @sap.display.format : 'NonNegative' + @sap.label : 'Sequence Number' + key OrdinalNumber : String(3) not null; + @sap.display.format : 'UpperCase' + @sap.label : 'Standard addr.' + @sap.quickinfo : 'Flag: this address is the default address' + IsDefaultEmailAddress : Boolean; + /** + * Internet mail address, also called e-mail address. + * + * Example: user.name@company.comThe Internet mail address is used to send mail via the Internet world-wide; the protocol used is SMTP (Simple Mail Transfer Protocol).The Internet mail address format is specified in various RFCs (Internet Request for Comment), including RFCs 821 and 822.This is not an IP address (192.56.30.6). + */ + @sap.label : 'Email Address' + EmailAddress : String(241); + /** + * This field is generated by the system from the complete Internet mail address and is stored in table ADR6. + * + * It contains the first 20 characters of the Internet mail address in normalized form, that is, without comment characters and converted into uppercase.The field cannot be maintained by the user or from an interface.The table ADR6 contains an index for this field.Using an Internet mail address, the corresponding key of table ADR6 and the owner of the address are determined (for example, business partner or user). + */ + @sap.display.format : 'UpperCase' + @sap.label : 'E-Mail Address' + @sap.quickinfo : 'E-Mail Address Search Field' + SearchEmailAddress : String(20); + /** + * Additional information about the communication connection + * + * You can maintain further information about the communication connection here. In the case of telephone numbers, for example, you can maintain the times at which the call recipient is available and those at which they are not, or you can specify whether the number is that of the secretary.The information is stored in table ADRT, regardless of language. + */ + @sap.label : 'Notes' + @sap.quickinfo : 'Communication link notes' + AddressCommunicationRemarkText : String(50); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Fax Number' +entity API_BUSINESS_PARTNER.A_AddressFaxNumber { + /** + * Internal key for identifying a Business Address Services address. + * + * For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Address Number' + key AddressID : String(10) not null; + /** + * Internal key for identifying a person in Business Address Services. + * + * For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Person number' + key Person : String(10) not null; + @sap.display.format : 'NonNegative' + @sap.label : 'Sequence Number' + key OrdinalNumber : String(3) not null; + /** + * If several addresses are maintained for one communication type, the user in the SAP System can be reached under one of these addresses. One address can be set as theStandard Address. + * + * The standard address is used for the following functions:When sending using the SMTP nodein SAPconnect, the home address of the communication type used is the one set as the sender address. The recipient can see this address in the sender information and can also reply directly to this address. The standard address is also transferred and can be used for incoming status notifications, for example.When sending using an RFC node in SAPconnect, the standard address of the communication type used is the one set as the sender address. The structure defined in the case of the RFC does not permit another address to be transferred, so the standard address is used for incoming status notifications too.The SAP users have the addresses of their exchange P.O. boxes in their standard communication type 'Internet Mail' as the home address and their Internet address in the SAP system as their standard address. Example:Home address: Bernard.Brown@Company.comStandard address: Bernard.Brown@System.Company.comSending using an SMTP nodeThe home address of the communication type 'Internet Mail' (Bernard.Brown@Company.com) is used as the sender address. If a reply is sent to this address the user receives directly in the exchange postbox.Sending using the RFC nodeThe standard address of the communication type 'Internet Mail' (Bernard.Brown@System.Company.com) is used as the sender address. If a reply is sent to this address, it arrives back to the SAP system.Example using a mail system groupThe users should get all messages in their Microsoft Exchange postboxes. In the SAP system the mail system group is activated for this using the setting "Send Messages to the Home Address".The address settings of the SAP users remain unchanged:Home address: Bernard.Brown@Company.comStandard address: Bernard.Brown@System.Company.comSending using an SMTP nodeThe home address of the communication type 'Internet Mail' (Bernard.Brown@Company.com) is used as the sender address. If a reply is sent to this address the user receives directly in the exchange postbox.Sending using the RFC nodeThe standard address of the communication type 'Internet Mail' (Bernard.Brown@System.Company.com) is used as the sender address. If a reply is sent to this address it arrives back in the SAP system. It is then forwarded using the mail system group to the home address and the user gets it in the exchange postbox. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Standard No.' + @sap.quickinfo : 'Standard Sender Address in this Communication Type' + IsDefaultFaxNumber : Boolean; + /** + * The country for the telephone number or fax number is maintained here. + * + * This specification is used to determine the correct country code. A normalized form of the telephone number or fax number is then derived and stored in a field for a program-driven search.In most cases, the telephone number or fax number refers directly to an address.If this is the case, when a new number is created, the country of the address is proposed.If this is not the case (for example, with address-independent communication data for a business partner), the country from the user parameter LND is proposed (if it is maintained). If the user parameter LND is not maintained, the country of the company address assigned in the user master data is proposed.If the country of the address changes, the country of the corresponding telephone number and fax address is not changed automatically.Example: A business partner moves abroad.If the telephone number is for a permanent connection, the telephone number also changes when the business partner moves and has to be maintained again in the system.If the telephone number is for a mobile telephone and the number is retained, the original country for this telephone number also has to be retained and must not be changed automatically to the new country of the address. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Country' + @sap.quickinfo : 'Country for telephone/fax number' + FaxCountry : String(3); + /** + * Fax number, consisting of dialling code and number, but without country dialling code. + * + * If the fax number consists of a company number and an extension, the extension must be entered in the field extension.Fax number, as it is to be dialled from within the same country.Enter the following for the number "01234/567-0":Fax: 01234/567Extension: 0Enter the following for the number "01234/567-891":Fax: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Fax: 012-345Extension: 678In the following cases, enter the complete number (without country dialing code) in the field Fax:No part of the number can be considered as an extension.You are not sure which part of the number can be considered as an extension. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Fax' + @sap.quickinfo : 'Fax number: dialling code+number' + FaxNumber : String(30); + /** + * Fax extension number + * + * If the fax number consists of a company number and an extension, the extension must be entered here.Enter the extensionThe following rules apply for the format of telephone and fax numbers:The length of the entries in the field Telephone and Extension (Fax and Extension) cannot be more than 24 characters in total.Leading spaces are not allowed in the field Telephone or Fax or in the field Extension.Valid characters are:Numbers (0123456789)Letters (ABCDEFGHIJKLMNOPQRSTUVWXYZ)Following other characters: /, (, ), - *, # and " " (space), but not as a leading space.If an + is entered as the first character, the system checks whether the specified number starts with a country code. If so, a warning message is displayed because the country code is automatically determined by the system and should not be stored in the Telephone number (Fax number) field.If an & is entered as the first character, the automatic check and formatting of the telephone number (fax number), as well as the determination of the country code, is suppressed.Enter the following for the number "01234/567-0":Fax: 01234/567Extension: 0Enter the following for the number "01234/567-891":Fax: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Fax: 012-345Extension: 678In the following cases, enter the complete number (without country dialing code) in the field Fax:No part of the number can be considered as an extension.You are not sure which part of the number can be considered as an extension. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Extension' + @sap.quickinfo : 'Fax no.: Extension' + FaxNumberExtension : String(10); + /** + * The content of this field is automatically calculated by the system based on fax number and country code components. + * + * This field is therefore not to be filled when Business Address Services function modules are called. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Fax Number' + @sap.quickinfo : 'Complete Number: Dialling Code+Number+Extension' + InternationalFaxNumber : String(30); + /** + * Additional information about the communication connection + * + * You can maintain further information about the communication connection here. In the case of telephone numbers, for example, you can maintain the times at which the call recipient is available and those at which they are not, or you can specify whether the number is that of the secretary.The information is stored in table ADRT, regardless of language. + */ + @sap.label : 'Notes' + @sap.quickinfo : 'Communication link notes' + AddressCommunicationRemarkText : String(50); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Home Page URL' +entity API_BUSINESS_PARTNER.A_AddressHomePageURL { + /** + * Internal key for identifying a Business Address Services address. + * + * For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Address Number' + key AddressID : String(10) not null; + /** + * Internal key for identifying a person in Business Address Services. + * + * For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Person number' + key Person : String(10) not null; + @sap.display.format : 'NonNegative' + @sap.label : 'Sequence Number' + key OrdinalNumber : String(3) not null; + @sap.display.format : 'Date' + @sap.label : 'from' + @sap.quickinfo : 'Valid-from date - in current Release only 00010101 possible' + key ValidityStartDate : Date not null; + @sap.display.format : 'UpperCase' + @sap.label : 'Standard addr.' + @sap.quickinfo : 'Flag: this address is the default address' + key IsDefaultURLAddress : Boolean not null; + @sap.display.format : 'UpperCase' + @sap.label : 'URI address' + @sap.quickinfo : 'URI address search field' + SearchURLAddress : String(50); + /** + * Additional information about the communication connection + * + * You can maintain further information about the communication connection here. In the case of telephone numbers, for example, you can maintain the times at which the call recipient is available and those at which they are not, or you can specify whether the number is that of the secretary.The information is stored in table ADRT, regardless of language. + */ + @sap.label : 'Notes' + @sap.quickinfo : 'Communication link notes' + AddressCommunicationRemarkText : String(50); + @sap.label : 'URI length' + @sap.quickinfo : 'URI field length' + URLFieldLength : Integer; + @sap.label : 'URI' + @sap.quickinfo : 'Universal Resource Identifier (URI)' + WebsiteURL : String(2048); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Phone Number' +entity API_BUSINESS_PARTNER.A_AddressPhoneNumber { + /** + * Internal key for identifying a Business Address Services address. + * + * For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Address Number' + key AddressID : String(10) not null; + /** + * Internal key for identifying a person in Business Address Services. + * + * For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Person number' + key Person : String(10) not null; + @sap.display.format : 'NonNegative' + @sap.label : 'Sequence Number' + key OrdinalNumber : String(3) not null; + /** + * The country for the telephone number or fax number is maintained here. + * + * This specification is used to determine the correct country code. A normalized form of the telephone number or fax number is then derived and stored in a field for a program-driven search.In most cases, the telephone number or fax number refers directly to an address.If this is the case, when a new number is created, the country of the address is proposed.If this is not the case (for example, with address-independent communication data for a business partner), the country from the user parameter LND is proposed (if it is maintained). If the user parameter LND is not maintained, the country of the company address assigned in the user master data is proposed.If the country of the address changes, the country of the corresponding telephone number and fax address is not changed automatically.Example: A business partner moves abroad.If the telephone number is for a permanent connection, the telephone number also changes when the business partner moves and has to be maintained again in the system.If the telephone number is for a mobile telephone and the number is retained, the original country for this telephone number also has to be retained and must not be changed automatically to the new country of the address. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Country' + @sap.quickinfo : 'Country for telephone/fax number' + DestinationLocationCountry : String(3); + /** + * If several addresses are maintained for one communication type, the user in the SAP System can be reached under one of these addresses. One address can be set as theStandard Address. + * + * The standard address is used for the following functions:When sending using the SMTP nodein SAPconnect, the home address of the communication type used is the one set as the sender address. The recipient can see this address in the sender information and can also reply directly to this address. The standard address is also transferred and can be used for incoming status notifications, for example.When sending using an RFC node in SAPconnect, the standard address of the communication type used is the one set as the sender address. The structure defined in the case of the RFC does not permit another address to be transferred, so the standard address is used for incoming status notifications too.The SAP users have the addresses of their exchange P.O. boxes in their standard communication type 'Internet Mail' as the home address and their Internet address in the SAP system as their standard address. Example:Home address: Bernard.Brown@Company.comStandard address: Bernard.Brown@System.Company.comSending using an SMTP nodeThe home address of the communication type 'Internet Mail' (Bernard.Brown@Company.com) is used as the sender address. If a reply is sent to this address the user receives directly in the exchange postbox.Sending using the RFC nodeThe standard address of the communication type 'Internet Mail' (Bernard.Brown@System.Company.com) is used as the sender address. If a reply is sent to this address, it arrives back to the SAP system.Example using a mail system groupThe users should get all messages in their Microsoft Exchange postboxes. In the SAP system the mail system group is activated for this using the setting "Send Messages to the Home Address".The address settings of the SAP users remain unchanged:Home address: Bernard.Brown@Company.comStandard address: Bernard.Brown@System.Company.comSending using an SMTP nodeThe home address of the communication type 'Internet Mail' (Bernard.Brown@Company.com) is used as the sender address. If a reply is sent to this address the user receives directly in the exchange postbox.Sending using the RFC nodeThe standard address of the communication type 'Internet Mail' (Bernard.Brown@System.Company.com) is used as the sender address. If a reply is sent to this address it arrives back in the SAP system. It is then forwarded using the mail system group to the home address and the user gets it in the exchange postbox. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Standard No.' + @sap.quickinfo : 'Standard Sender Address in this Communication Type' + IsDefaultPhoneNumber : Boolean; + /** + * Telephone number, consisting of dialling code and number, but without country dialling code. + * + * If the telephone number consists of a company number and an extension, the extension must be entered in the field extension.Telephone number, as it is dialled from within the country.For the number "01234/567-0" enter the following:Telephone: 01234/567Estension: 0For the number "01234/567-891" enter the following:Telephone: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Telepone: 012-345Extension: 678In the following cases enter the complete number (without country dialling code) in the field Telephone:No part of the number can be regarded as an extension.You are not sure which part of the number can be regarded as an extension. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Telephone' + @sap.quickinfo : 'Telephone no.: dialling code+number' + PhoneNumber : String(30); + /** + * Telephone extension number + * + * If the telephone number consists of a company number and an extension, the extension should be entered here.Enter the extension.The following rules apply for the format of telephone and fax numbers:The length of the entries in the field Telephone and Extension (Fax and Extension) cannot be more than 24 characters in total.Leading spaces are not allowed in the field Telephone or Fax or in the field Extension.Valid characters are:Numbers (0123456789)Letters (ABCDEFGHIJKLMNOPQRSTUVWXYZ)Following other characters: /, (, ), - *, # and " " (space), but not as a leading space.If an + is entered as the first character, the system checks whether the specified number starts with a country code. If so, a warning message is displayed because the country code is automatically determined by the system and should not be stored in the Telephone number (Fax number) field.If an & is entered as the first character, the automatic check and formatting of the telephone number (fax number), as well as the determination of the country code, is suppressed.For the number "01234/567-0" enter the following:Telephone: 01234/567Estension: 0For the number "01234/567-891" enter the following:Telephone: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Telepone: 012-345Extension: 678In the following cases enter the complete number (without country dialling code) in the field Telephone:No part of the number can be regarded as an extension.You are not sure which part of the number can be regarded as an extension. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Extension' + @sap.quickinfo : 'Telephone no.: Extension' + PhoneNumberExtension : String(10); + /** + * The content of this field is automatically calculated by the system based on the telephone number and country code components. + * + * This field is therefore not to be filled when Business Address Services function modules are called. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Telephone Number' + @sap.quickinfo : 'Complete Number: Dialling Code+Number+Extension' + InternationalPhoneNumber : String(30); + /** + * This field specifies whether the telephone number is a mobile telephone number. + * + * ' ' : The telephone number is a fixed-line telephone'1' : The telephone number is the standard fixed-line telephone'2' : The telephone nubmer is a mobile telephone'3' : The telephone number is the standard mobile telephoneEither the standard fixed-line telephone number or the standard mobile telephone number is also the standard telephone number (FLGDEFAULT = 'X').In older data sets, this field may have also have the value ' ' for the standard fixed-line telephone. In this case, however, FLGDEFAULT is always 'X'.In Customizing, you can specify whether the SMS-compatible indicator is to be proposed for new mobile telephone numbers created in dialog by choosing General Settings -> Set countries -> Define Mobile Telephone Attributes for each country. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Mobile phone' + @sap.quickinfo : 'Indicator: Telephone is a Mobile Telephone' + PhoneNumberType : String(1); + /** + * Additional information about the communication connection + * + * You can maintain further information about the communication connection here. In the case of telephone numbers, for example, you can maintain the times at which the call recipient is available and those at which they are not, or you can specify whether the number is that of the secretary.The information is stored in table ADRT, regardless of language. + */ + @sap.label : 'Notes' + @sap.quickinfo : 'Communication link notes' + AddressCommunicationRemarkText : String(50); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.creatable : 'false' +@sap.updatable : 'false' +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Contact Person Address' +entity API_BUSINESS_PARTNER.A_BPContactToAddress { + /** The business partner relationship number is an internal number that identifies the business partner relationship set. */ + @sap.display.format : 'UpperCase' + @sap.label : 'BP Relationship No.' + @sap.quickinfo : 'BP Relationship Number' + key RelationshipNumber : String(12) not null; + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartnerCompany : String(10) not null; + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartnerPerson : String(10) not null; + @sap.display.format : 'Date' + @sap.label : 'Valid To' + @sap.quickinfo : 'Validity Date (Valid To)' + key ValidityEndDate : Date not null; + /** + * Internal key for identifying a Business Address Services address. + * + * For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Address Number' + key AddressID : String(10) not null; + /** + * Internal key for identifying a Business Address Services address. + * + * For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Address Number' + AddressNumber : String(10); + /** + * Additional address field which is printed above the Street line. + * + * The Street address contains two lines above the street and two lines below the street.See Print the Street address. + */ + @sap.label : 'Street 3' + AdditionalStreetPrefixName : String(40); + /** + * Additional address field which is printed under the Street line. + * + * The Street address has two lines above the street and two lines below the steet.See Print the Street address. + */ + @sap.label : 'Street 5' + AdditionalStreetSuffixName : String(40); + /** + * Time zone as part of an address. + * + * The time zone is automatically determined by the system in address maintenance if time zone Customizing is maintained.It depends on the country and the region. (Region means state, province or county, depending on the country)The automatic determination is only made if there is no value in the time zone field. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Time zone' + @sap.quickinfo : 'Address time zone' + AddressTimeZone : String(6); + /** + * Part of the address (c/o = care of) if the recipient is different from the occupant and the names are not similar (e.g. subtenants). + * + * Put the country-specific code (e.g. c/o) in front of the name of the occupant. This is not automatically done in the print format, like the language-specific word "PO Box".John Smithc/o David BrownThis field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.label : 'c/o' + @sap.quickinfo : 'c/o name' + CareOfName : String(40); + @sap.display.format : 'UpperCase' + @sap.label : 'City Code' + @sap.quickinfo : 'City code for city/street file' + CityCode : String(12); + /** + * City name as part of the address. + * + * The city name is saved redundantly in another database field in upper- case letters, for search help.If the Postal regional structure ('city file') is active, the city name is checked against the Cities defined in the regional structure. + */ + @sap.label : 'City' + CityName : String(40); + /** + * Postal code that is assigned directly to one company (= company postal code = major customer postal code). + * + * This field is used for countries where major companies are assigned their own postal code by the national post office.This postal code has to be entered in the field "Company Postal Code". Postal codes for group major customers, however, have to be entered in the field "PO Box Postal Code", since individual customers with a shared postal code for group major customers are differentiated by means of their PO box. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Company Postal Code' + @sap.quickinfo : 'Company Postal Code (for Large Customers)' + CompanyPostalCode : String(10); + /** + * The country key contains information which the system uses to check entries such as the length of the postal code or bank account number. + * + * The two-character ISO code in accordance with ISO 3166, which is delivered by SAP as a default, is usually used.It could also be the vehicle license plate country-code or a typical country key, for example, in Germany the Federal statistics office key.The country keys are determined at system installation in the global settings.The definition of the country key in the SAP system does not have to match political or government entities.Since the country key does not have to correspond to the ISO code in all installations, programs that differ according to certain values of the country key cannot query the country key T005-LAND1, but have to program based on the ISO code T005 INTCA. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Country Key' + Country : String(3); + /** + * Specifies the county’s name + * + * This field is used to store the county’s name. You can enter the name of the county in this field. + */ + @sap.label : 'County' + County : String(40); + /** + * The delivery service is part of the PO box address. + * + * Some countries offer different services in addition to regular postal delivery and PO boxes, for example the Private Bag or Response Bag. If an address is related to one of these delivery services, the information about this particular delivery service has to be entered in the corresponding fields.In the field "Number of Delivery Service," the number of the Private Bag, Response Bag, or other relevant service has to be entered. Entering a number is not mandatory for each delivery service.For each address, either the information about the PO box or the information about the delivery service can be entered, but not both types of information at the same time.Mr PickeringPrivate Bag 106999Timaru 7942Delivery services will only be taken into account for address formatting in countries in which they are commonly used in addition to regular postal delivery and PO boxes, for example, in Australia, New Zealand, and the USA. In all other countries, these fields will not be taken into account for address formatting. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Delivery Service No.' + @sap.quickinfo : 'Number of Delivery Service' + DeliveryServiceNumber : String(10); + /** + * The delivery service is part of the PO box address. + * + * Some countries offer different services in addition to regular postal delivery and PO boxes, for example the Private Bag or Response Bag. If an address is related to one of these delivery services, the information about this particular delivery service has to be entered in the corresponding fields.In the field "Type of Delivery Service," the type of the delivery service has to be entered.For each address, either the information about the PO box or the information about the delivery service can be entered, but not both types of information at the same time.Mr PickeringPrivate Bag 106999Timaru 7942Delivery services will only be taken into account for address formatting in countries in which they are commonly used in addition to regular postal delivery and PO boxes, for example, in Australia, New Zealand, and the USA. In all other countries, these fields will not be taken into account for address formatting. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Delvry Serv Type' + @sap.quickinfo : 'Type of Delivery Service' + DeliveryServiceTypeCode : String(4); + /** + * City or District supplement + * + * In some countries, this entry is appended with a hyphen to the city name by the automatic address formatting, other countries, it is output on a line of its own or (e.g. in the USA) not printed.See the examples in the Address Layout Key documentation. + */ + @sap.label : 'District' + District : String(40); + /** + * Key for form of address text. + * + * You can also define a form of address text in Customizing.The form of address text can be maintained in different languages. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Title' + @sap.quickinfo : 'Form-of-Address Key' + @sap.creatable : 'false' + @sap.updatable : 'false' + FormOfAddress : String(4); + /** + * This field contains the full name or formatted name of a party. + * + * For organizations or document addresses, typically the fields Name1 and Name2 are concatenated.For persons the field contains the formatted name according to country specific rules. It corresponds e.g. to the content of the fields BUT000-NAME1_TEXT or ADRP-NAME_TEXT. + */ + @sap.label : 'Full Name' + @sap.quickinfo : 'Full name of a party (Bus. Partner, Org. Unit, Doc. address)' + @sap.creatable : 'false' + @sap.updatable : 'false' + FullName : String(80); + /** + * City of residence which is different from the postal city + * + * In some countries, the residential city is required if it differs from the postal city.In the USA, the official street indexes, against which data can be checked, are based on the residential city, not the postal city, which may be different.It is the same in France, where a postally correct address must contain the residential city in a separate line above the postal city, if it differs from the postal city.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.label : 'Different City' + @sap.quickinfo : 'City (different from postal city)' + HomeCityName : String(40); + /** + * House number as part of an address. + * + * It is printed in the Street line.Other supplementary street information can be entered in the House number supplement or one of the Street2, Street3, Street4 or Street5 fields. See Print the Street address.A house number (e.g. 117) or a house number with supplement (e.g. 117a), or a house number range (e.g. 16-20), can be maintained in this field. + */ + @sap.label : 'House Number' + HouseNumber : String(10); + /** + * House number supplement as part of an address, e.g. + * + * App. 17 orSuite 600.It is printed in the Street line.Further Street supplements can be put in one of the fields Street2, Street3, Street4 or Street5.See Print the Street address. + */ + @sap.label : 'Supplement' + @sap.quickinfo : 'House number supplement' + HouseNumberSupplementText : String(10); + /** + * The language key indicates + * + * - the language in which texts are displayed,- the language in which you enter texts,- the language in which the system prints texts. + */ + @sap.label : 'Language Key' + Language : String(2); + /** + * PO Box number as part of an address. + * + * Only enter the PO Box number in this field. The text "PO Box" is provided in the recipient language by the system when you print the address.When you print an address, the "Street address" and the "PO Box address" are distinguished. The print program determines which of them has priority if both are maintained in an address record.Besides the PO Box number, the PO Box address uses the following fields:PO Box postal code, if specified (otherwise the normal postal code)PO Box city, if specified (otherwise the normal city)PO Box region, if specified (otherwise the normal region)PO Box country, if specified (otherwise the normal country)If the address is a "PO Box" (without a number), do not fill the "PO Box" field. Select the "PO Box w/o Number" indicator instead.You can also enter a company postal code for organizational addresses, instead of a PO Box. A separate field is predefined for this entry.For general information and examples about address formatting, see the documentation on the Address Structure Key. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'PO Box' + POBox : String(10); + /** + * Different city for the PO Box as an address component. + * + * The PO Box city can be entered here if it is different from the address city.If the address is only a PO Box address, enter the city in the normal city field.If the address contains two different city names for the address and the PO Box address, use this field. + */ + @sap.label : 'PO Box City' + @sap.quickinfo : 'PO Box city' + POBoxDeviatingCityName : String(40); + /** + * Different PO Box country in address. + * + * The PO Box country can be entered here, if it is different from the street address country.If the address only has a PO Box address, the country is in the normal country field.Use this field if the address has two different country values for the street address and the PO Box address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'PO box country' + POBoxDeviatingCountry : String(3); + /** + * Different Region for PO Box in an address. + * + * Enter the PO Box Region here, if it differs from the street address region.If the address only has a PO Box address, the Region in in the normal Region field.Use this field if the address has two different Region values for the street address and the PO Box address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'PO Box Region' + @sap.quickinfo : 'Region for PO Box (Country, State, Province, ...)' + POBoxDeviatingRegion : String(3); + /** + * PO Box address without PO Box number flag. + * + * Only the word 'PO Box' is output in PO Box addresses without PO Box number.Set this flag for a PO Box address without PO Box number.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'PO Box w/o No.' + @sap.quickinfo : 'Flag: PO Box Without Number' + POBoxIsWithoutNumber : Boolean; + /** + * The PO box lobby is part of the PO box address. + * + * In some countries, entering a PO box, postal code and city is not sufficient to uniquely identify a PO box, because the same PO box number is assigned multiple times in some cities.Therefore, additional information might be required to determine the post office of the PO box in question. This information can be entered in the field "PO Box Lobby."Mr NellingPO Box 4099HighfieldTimaru 7942The PO box lobby will only be taken into account for address formatting in countries in which it is commonly used in addition to regular postal delivery and PO boxes, for example, in Canada or New Zealand. In all other countries, this field will not be taken into account for address formatting. + */ + @sap.label : 'PO Box Lobby' + POBoxLobbyName : String(40); + /** + * Postal code that is required for a unique assignment of the PO box. + * + * This field is used for countries where a different postal code applies to mail that is sent to the PO box rather than to the street address of a particular business partner.Postal codes for group major customers also have to be entered in the field for the PO box postal code since individual customers with a shared postal code for group major customers are differentiated by means of the PO box. Postal codes for major customers (= company postal codes), however, are assigned to one customer only and have to be entered in the field 'Company Postal Code'. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'PO Box Postal Code' + POBoxPostalCode : String(10); + /** + * Internal key for identifying a person in Business Address Services. + * + * For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Person number' + @sap.creatable : 'false' + @sap.updatable : 'false' + Person : String(10); + /** + * Postal code as part of the address + * + * If different postal codes are maintained for the PO Box and Street address of an address, this field contains the Street address postal code. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Postal Code' + @sap.quickinfo : 'City Postal Code' + PostalCode : String(10); + /** + * Communication method with which you can exchange documents and messages with a business partner. + * + * In Business Address Services, you can specify a standard communication method that can be used by programs to determine the means of communication for sending messages.One business partner wants all messages by fax, another by e-mail.The application context can restrict the possible methods of communication. For example, invitations should perhaps only be sent by post because of enclosures, whereas minutes can be sent by post, fax or e-mail.Communication strategies can be defined for this purpose and applied in application contexts. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Comm. Method' + @sap.quickinfo : 'Communication Method (Key) (Business Address Services)' + PrfrdCommMediumType : String(3); + /** + * In some countries, the region forms part of the address. The meaning depends on the country. + * + * The automatic address formatting function prints the region in addresses in the USA, Canada, Italy, Brazil or Australia, and the county in Great Britain.For more information, see the examples in the documentation on the Address Layout Key.Meaning of the regional code in ...Australia -> ProvinceBrazil -> StateCanada -> ProvinceGermany -> StateGreat Britain -> CountyItaly -> ProvinceJapan -> PrefectureSwitzerland -> CantonUSA -> State + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Region' + @sap.quickinfo : 'Region (State, Province, County)' + Region : String(3); + /** + * Street name as part of the address. + * + * The street name is saved, redundantly in upper case in another database field, for search help purposes.There are other fields for address parts which can be printed above or below the street. See Print the Street address.The house number and other supplements are usually maintained in their own fields. See Formatting the Street line. + */ + @sap.label : 'Street' + StreetName : String(60); + /** + * Additional address field which is printed above the Street line. + * + * The Street address contains two lines above the street and two lines below the street.See Print the Street address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.label : 'Street 2' + StreetPrefixName : String(40); + /** + * Additional address field which is printed below the Street line. + * + * The Street address contains two lines above the street and two lines below the street.See Print the Street address. + */ + @sap.label : 'Street 4' + StreetSuffixName : String(40); + /** Specifies the tax jurisdiction. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Jurisdiction' + TaxJurisdiction : String(15); + /** + * Sales and distribution: + * + * Regional zone of Goods recipient.Purchasing:Regional zone of supplier.You can define regional zones to suit the requirements of your own business and country.Sales and distributionthe system automatically proposes a suitable route by using the transportation zone of the goods recipient in combination with other information about the delivery, such as theCountries of origin and destinationShipping conditionsTransportation groupIn the USA, for example, you can define regional zones to correspond to the US postal zip codes. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Transportation Zone' + @sap.quickinfo : 'Transportation zone to or from which the goods are delivered' + TransportZone : String(10); + @cds.ambiguous : 'missing on condition?' + to_EmailAddress : Association to many API_BUSINESS_PARTNER.A_AddressEmailAddress { }; + @cds.ambiguous : 'missing on condition?' + to_FaxNumber : Association to many API_BUSINESS_PARTNER.A_AddressFaxNumber { }; + @cds.ambiguous : 'missing on condition?' + to_MobilePhoneNumber : Association to many API_BUSINESS_PARTNER.A_AddressPhoneNumber { }; + @cds.ambiguous : 'missing on condition?' + to_PhoneNumber : Association to many API_BUSINESS_PARTNER.A_AddressPhoneNumber { }; + @cds.ambiguous : 'missing on condition?' + to_URLAddress : Association to many API_BUSINESS_PARTNER.A_AddressHomePageURL { }; +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.creatable : 'false' +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Function and Department' +entity API_BUSINESS_PARTNER.A_BPContactToFuncAndDept { + /** The business partner relationship number is an internal number that identifies the business partner relationship set. */ + @sap.display.format : 'UpperCase' + @sap.label : 'BP Relationship No.' + @sap.quickinfo : 'BP Relationship Number' + key RelationshipNumber : String(12) not null; + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartnerCompany : String(10) not null; + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartnerPerson : String(10) not null; + @sap.display.format : 'Date' + @sap.label : 'Valid To' + @sap.quickinfo : 'Validity Date (Valid To)' + key ValidityEndDate : Date not null; + /** + * Identifies the function that a person has within a company. + * + * This is a contact person attribute that you can define in Customizing.Personnel managerSecretary + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Function' + @sap.quickinfo : 'Function of partner' + ContactPersonFunction : String(4); + /** + * Name of the department of a business partner for your internal usage. + * + * The name given by the business partner to this particular department may differ from the name that you use. You can enter the name given by the business partner in the field company department.This is a contact person attribute that you can define in Customizing.For your purposes, the department name is "Sales". The business partner names the same department "Sales South". + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Department' + ContactPersonDepartment : String(4); + /** + * Telephone number, consisting of dialling code and number, but without country dialling code. + * + * If the telephone number consists of a company number and an extension, the extension must be entered in the field extension.Telephone number, as it is dialled from within the country.For the number "01234/567-0" enter the following:Telephone: 01234/567Estension: 0For the number "01234/567-891" enter the following:Telephone: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Telepone: 012-345Extension: 678In the following cases enter the complete number (without country dialling code) in the field Telephone:No part of the number can be regarded as an extension.You are not sure which part of the number can be regarded as an extension. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Telephone' + @sap.quickinfo : 'Telephone no.: dialling code+number' + PhoneNumber : String(30); + /** + * Telephone extension number + * + * If the telephone number consists of a company number and an extension, the extension should be entered here.Enter the extension.The following rules apply for the format of telephone and fax numbers:The length of the entries in the field Telephone and Extension (Fax and Extension) cannot be more than 24 characters in total.Leading spaces are not allowed in the field Telephone or Fax or in the field Extension.Valid characters are:Numbers (0123456789)Letters (ABCDEFGHIJKLMNOPQRSTUVWXYZ)Following other characters: /, (, ), - *, # and " " (space), but not as a leading space.If an + is entered as the first character, the system checks whether the specified number starts with a country code. If so, a warning message is displayed because the country code is automatically determined by the system and should not be stored in the Telephone number (Fax number) field.If an & is entered as the first character, the automatic check and formatting of the telephone number (fax number), as well as the determination of the country code, is suppressed.For the number "01234/567-0" enter the following:Telephone: 01234/567Estension: 0For the number "01234/567-891" enter the following:Telephone: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Telepone: 012-345Extension: 678In the following cases enter the complete number (without country dialling code) in the field Telephone:No part of the number can be regarded as an extension.You are not sure which part of the number can be regarded as an extension. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Extension' + @sap.quickinfo : 'Telephone no.: Extension' + PhoneNumberExtension : String(10); + /** + * Fax number, consisting of dialling code and number, but without country dialling code. + * + * If the fax number consists of a company number and an extension, the extension must be entered in the field extension.Fax number, as it is to be dialled from within the same country.Enter the following for the number "01234/567-0":Fax: 01234/567Extension: 0Enter the following for the number "01234/567-891":Fax: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Fax: 012-345Extension: 678In the following cases, enter the complete number (without country dialing code) in the field Fax:No part of the number can be considered as an extension.You are not sure which part of the number can be considered as an extension. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Fax' + @sap.quickinfo : 'Fax number: dialling code+number' + FaxNumber : String(30); + /** + * Fax extension number + * + * If the fax number consists of a company number and an extension, the extension must be entered here.Enter the extensionThe following rules apply for the format of telephone and fax numbers:The length of the entries in the field Telephone and Extension (Fax and Extension) cannot be more than 24 characters in total.Leading spaces are not allowed in the field Telephone or Fax or in the field Extension.Valid characters are:Numbers (0123456789)Letters (ABCDEFGHIJKLMNOPQRSTUVWXYZ)Following other characters: /, (, ), - *, # and " " (space), but not as a leading space.If an + is entered as the first character, the system checks whether the specified number starts with a country code. If so, a warning message is displayed because the country code is automatically determined by the system and should not be stored in the Telephone number (Fax number) field.If an & is entered as the first character, the automatic check and formatting of the telephone number (fax number), as well as the determination of the country code, is suppressed.Enter the following for the number "01234/567-0":Fax: 01234/567Extension: 0Enter the following for the number "01234/567-891":Fax: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Fax: 012-345Extension: 678In the following cases, enter the complete number (without country dialing code) in the field Fax:No part of the number can be considered as an extension.You are not sure which part of the number can be considered as an extension. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Extension' + @sap.quickinfo : 'Fax no.: Extension' + FaxNumberExtension : String(10); + /** + * Internet mail address, also called e-mail address. + * + * Example: user.name@company.comThe Internet mail address is used to send mail via the Internet world-wide; the protocol used is SMTP (Simple Mail Transfer Protocol).The Internet mail address format is specified in various RFCs (Internet Request for Comment), including RFCs 821 and 822.This is not an IP address (192.56.30.6). + */ + @sap.label : 'Email Address' + EmailAddress : String(241); + /** + * A relationship may exist between two business partners. The business partner relationship category characterizes the features of the relationship. + * + * A distinction is made between a one-way and an undirected business partner relationship category. In a one-way relationship category, the relationship extends from one partner to another, but not vice versa.Marriage (undirected)Employee (one-way)Contact person (one-way) + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Relationship Cat.' + @sap.quickinfo : 'Business Partner Relationship Category' + RelationshipCategory : String(6); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Address Usage' +entity API_BUSINESS_PARTNER.A_BuPaAddressUsage { + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartner : String(10) not null; + @odata.Type : 'Edm.DateTimeOffset' + @sap.label : 'Valid To' + @sap.quickinfo : 'Validity End of a Business Partner Address Usage' + key ValidityEndDate : DateTime not null; + /** + * Business partner attribute, which you can use to distinguish between various addresses by defining the address usage for communication with business partners. + * + * Maintain the usage types for addresses (address types) in Customizing.You can create a short description and a name for the address type.When maintaining business partners you can use the function address usage to assign business partner addresses to address types.If necessary, you can set the indicator for multiple use in Customizing.Correspondence addressDelivery address + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Address Type' + key AddressUsage : String(10) not null; + /** + * Internal key for identifying a Business Address Services address. + * + * For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Address Number' + key AddressID : String(10) not null; + @odata.Type : 'Edm.DateTimeOffset' + @sap.label : 'Valid From' + @sap.quickinfo : 'Validity Start of a Business Partner Address Usage' + ValidityStartDate : DateTime; + /** + * Establishes which is the standard address for an address usage. + * + * Several addresses per period can be assigned to an address usage.If this is the case, then this indicator controls which of the assigned addresses should be the standard address of the relevant usage. This is determined automatically when the address usage is accessed. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Standard Usage' + @sap.quickinfo : 'Indicator: Standard Address Usage' + StandardUsage : Boolean; + /** + * You can use authorization groups to stipulate which business partners a user is allowed to process. + * + * Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization Group' + AuthorizationGroup : String(4); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Identification' +entity API_BUSINESS_PARTNER.A_BuPaIdentification { + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartner : String(10) not null; + /** + * A document (such as an ID card or driver's license) or an entry in a system of records (such as a commercial register) whose key can be stored as an attribute for a business partner. + * + * The identification type is for classifying identification numbers.You can define the identification types and their descriptions in Customizing.You can also specify for which business partner category an ID type should be valid.If necessary, assign the identification type to an Identification Category.You can only assign one identification type to an identification category. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Identification Type' + key BPIdentificationType : String(6) not null; + /** Number that serves to identify a business partner, such as driver's license, or ID card number. */ + @sap.display.format : 'UpperCase' + @sap.label : 'ID number' + @sap.quickinfo : 'Identification Number' + key BPIdentificationNumber : String(60) not null; + /** Institution that adminsters or assigns an ID number. */ + @sap.label : 'Responsible Institn' + @sap.quickinfo : 'Responsible Institution for ID Number' + BPIdnNmbrIssuingInstitute : String(40); + /** Date on which the ID number was registered or assigned by the appropriate authority. */ + @sap.display.format : 'Date' + @sap.label : 'Entry date' + @sap.quickinfo : 'Date of Entry for ID Number' + BPIdentificationEntryDate : Date; + /** Country in which an ID number was assigned, or in which the number is valid. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Country' + @sap.quickinfo : 'Country in Which ID Number is Valid or Was Assigned' + Country : String(3); + /** + * In some countries, the region forms part of the address. The meaning depends on the country. + * + * The automatic address formatting function prints the region in addresses in the USA, Canada, Italy, Brazil or Australia, and the county in Great Britain.For more information, see the examples in the documentation on the Address Layout Key.Meaning of the regional code in ...Australia -> ProvinceBrazil -> StateCanada -> ProvinceGermany -> StateGreat Britain -> CountyItaly -> ProvinceJapan -> PrefectureSwitzerland -> CantonUSA -> State + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Region' + @sap.quickinfo : 'Region (State, Province, County)' + Region : String(3); + /** This date marks the start of validity of an ID number. */ + @sap.display.format : 'Date' + @sap.label : 'Valid from' + @sap.quickinfo : 'Validity Start for ID Number' + ValidityStartDate : Date; + /** This date marks the end of validity of an ID number. */ + @sap.display.format : 'Date' + @sap.label : 'Valid To' + @sap.quickinfo : 'Validity End for ID Number' + ValidityEndDate : Date; + /** + * You can use authorization groups to stipulate which business partners a user is allowed to process. + * + * Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization Group' + AuthorizationGroup : String(4); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Industry' +entity API_BUSINESS_PARTNER.A_BuPaIndustry { + /** + * Describes an industry. + * + * An industry is a classification of companies according to their main business activity. For example, you can use Commerce, Banking, Services, Industry, Healthcare, Public Sector, Media, and so on, as industries.You can define industries along with their descriptions in Customizing.Assign the industry key to an industry key system. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Industry' + key IndustrySector : String(10) not null; + /** + * Serves to combine and categorize several industries into a group. + * + * You can create different industry systems, each with its own catalog of industries, whereby an industry can be assigned to several industry systems.You have to select one industry system as the standard industry system. This is then automatically displayed in the initial screen for the maintenance of industry data.You can define an industry system along with its description in Customizing. You can assign several industry systems to a business partner.If you choose the button All Industry Systems, you can access all the industry systems defined in the Customizing using the input help. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Industry System' + key IndustrySystemType : String(4) not null; + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartner : String(10) not null; + /** + * Identifies the industry in an industry system that can be defined as the standard industry. + * + * It is recommended that you define an industry within an industry system as the standard industry, because only the standard industries can be determined at the interfaces to BW or the APIs, for example.This means that even if only one industry exists within an industry system, it should be indicated as the standard industry as this this information cannot be determined otherwise. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Standard Industry' + @sap.quickinfo : 'Industry is Standard for BP in Industry System' + IsStandardIndustry : String(1); + @sap.label : 'Description' + IndustryKeyDescription : String(100); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Business Partner' +entity API_BUSINESS_PARTNER.A_BusinessPartner { + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartner : String(10) not null; + /** Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer' + @sap.quickinfo : 'Customer Number' + @sap.creatable : 'false' + @sap.updatable : 'false' + Customer : String(10); + /** Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Supplier' + @sap.quickinfo : 'Account Number of Supplier' + @sap.creatable : 'false' + @sap.updatable : 'false' + Supplier : String(10); + /** + * Key for academic title. + * + * You can define a key for an academic title in Customizing. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Academic Title 1' + @sap.quickinfo : 'Academic Title: Key' + AcademicTitle : String(4); + /** + * You can use authorization groups to stipulate which business partners a user is allowed to process. + * + * Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization Group' + AuthorizationGroup : String(4); + /** + * Category under which a business partner is classified. + * + * You can distinguish between the following business partner categories:OrganizationNatural personGroup of natural persons or organizationsThe processing screens for the business partner categories are set up differently.So, for example, the screen for an organization contains the field Legal form, but this is not needed in the screen for a natural person. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'BP Category' + @sap.quickinfo : 'Business Partner Category' + BusinessPartnerCategory : String(1); + @sap.creatable : 'false' + @sap.updatable : 'false' + BusinessPartnerFullName : String(81); + /** + * Classification assigned when creating a business partner. + * + * Assign each business partner to a grouping when you create the business partner. The grouping determines the number range. You cannot change the assignment afterwards.You can define the groupings, their descriptions, the associated number range and other attributes in Customizing.You can define standard groupings for the internal and the external number assignment.For each grouping create a number range.When you create a business partner, the entry in the grouping field determines whether and how an entry is made in the business partner number field. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Grouping' + @sap.quickinfo : 'Business Partner Grouping' + BusinessPartnerGrouping : String(4); + @sap.creatable : 'false' + @sap.updatable : 'false' + BusinessPartnerName : String(81); + @sap.label : 'BP GUID' + @sap.quickinfo : 'Business Partner GUID' + @sap.creatable : 'false' + @sap.updatable : 'false' + BusinessPartnerUUID : UUID; + /** + * Correspondence language (written) for business partners in the 'Person' category. Maintain the correspondence language for business partners in the 'Organization' and 'Group' category with the address (communication). + * + * When transferring data (direct input), make sure that for a'Person', the field 'LANGU_CORR' and for an'Organization' or "Group" the field 'LANGU'has an entry. + */ + @sap.label : 'Correspondence lang.' + @sap.quickinfo : 'Business Partner: Correspondence Language' + CorrespondenceLanguage : String(2); + @sap.display.format : 'UpperCase' + @sap.label : 'Created By' + @sap.quickinfo : 'User who created the object' + @sap.creatable : 'false' + @sap.updatable : 'false' + CreatedByUser : String(12); + @sap.display.format : 'Date' + @sap.label : 'Created on' + @sap.quickinfo : 'Date on which the object was created' + @sap.creatable : 'false' + @sap.updatable : 'false' + CreationDate : Date; + @sap.label : 'Created at' + @sap.quickinfo : 'Time at which the object was created' + @sap.creatable : 'false' + @sap.updatable : 'false' + CreationTime : Time; + @sap.label : 'First Name' + @sap.quickinfo : 'First Name of Business Partner (Person)' + FirstName : String(40); + /** + * Key for form of address text. + * + * You can also define a form of address text in Customizing.The form of address text can be maintained in different languages. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Title' + @sap.quickinfo : 'Form-of-Address Key' + FormOfAddress : String(4); + /** + * An industry sector is the term used to classify a company according to its main business activity. + * + * You can assign an industry sector to business partners in the category 'Organization'RetailBanksServicesIndustryHealth servicePublic sectorMedia + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Industry sector' + Industry : String(10); + /** + * Here you enter the first 7 digits of the international location number. + * + * The International Location Number (ILN) is assigned (in Germany by the Centrale for Coorganisation GmbH)) when a company is founded. It consists of 13 digits, the last digit being the check digit. There are two categories of location numbers:Participants who only need an ILN to cleary and unmistakably identify themselves for communication with the business partner are given a category 1 ILN. This cannot be used to identify articles by means of EAN.Participants who wish to assign the location numbers for their own enterprise areas are given a category 2 ILN. For a category 2 ILN, digits 1 to 7 are described as basis number. This is used as basis for the creation of article numbers (EAN). + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Int. location no. 1' + @sap.quickinfo : 'International location number (part 1)' + InternationalLocationNumber1 : String(7); + /** + * Here, you enter digits 8-12 of the 13-digit international location number. + * + * The international location number (ILN) is assigned when establishing a company (by the "Zentrale für Coorganisation GmbH" in Germany). It consists of 13 digits, the last of which is the check digit. There are two types of international location numbers:Subscribers who only need one ILN to identify themselves in communication with the business partner are given an ILN of type 1. These cannot be used for identifying articles by means of EAN.Subscribers who need to assign location numbers for their own company areas are given an ILN of type 2. Positions 1 through 7 of the ILN type 2 are known as the basis number. This basis number forms the basis for article numbers (EAN). + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Int. location no. 2' + @sap.quickinfo : 'International location number (Part 2)' + InternationalLocationNumber2 : String(5); + @sap.display.format : 'UpperCase' + @sap.label : 'Female' + @sap.quickinfo : 'Selection: Business partner is female' + IsFemale : Boolean; + @sap.display.format : 'UpperCase' + @sap.label : 'Male' + @sap.quickinfo : 'Selection: Business partner is male' + IsMale : Boolean; + /** + * Indicator through which a distinction between natural and legal persons can be made during tax reporting. + * + * Is used in Italy and Mexico ,among other countries.Brasil: If the indicator is not set, 'CGC' is relevant in tax number 1. If the indicator is set, 'CPF' is relevant in tax number 2.Colombia: In the case of some natural persons, the NIT number does not have a check digit. In this case you should set this indicator and the check is deactivated. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Natural Person' + @sap.quickinfo : 'Business Partner Is a Natural Person Under the Tax Laws' + IsNaturalPerson : String(1); + @sap.display.format : 'UpperCase' + @sap.label : 'Unknown' + @sap.quickinfo : 'Selection: Sex of business partner is not known' + IsSexUnknown : Boolean; + @sap.display.format : 'UpperCase' + @sap.label : 'Gender' + @sap.quickinfo : 'Gender of Business Partner (Person)' + GenderCodeName : String(1); + /** + * Language for verbal communication with a business partner. + * + * This language may differ from the language(s) defined for written correspondence. + */ + @sap.label : 'Language' + @sap.quickinfo : 'Business partner: Language' + Language : String(2); + @sap.display.format : 'Date' + @sap.label : 'Changed on' + @sap.quickinfo : 'Date when object was last changed' + @sap.creatable : 'false' + @sap.updatable : 'false' + LastChangeDate : Date; + @sap.label : 'Changed at' + @sap.quickinfo : 'Time at which object was last changed' + @sap.creatable : 'false' + @sap.updatable : 'false' + LastChangeTime : Time; + @sap.display.format : 'UpperCase' + @sap.label : 'Changed by' + @sap.quickinfo : 'Last user to change object' + @sap.creatable : 'false' + @sap.updatable : 'false' + LastChangedByUser : String(12); + @sap.label : 'Last Name' + @sap.quickinfo : 'Last Name of Business Partner (Person)' + LastName : String(40); + /** + * Denotes certain legal norms that are of significance for the organization of a company. + * + * For business partners in the category "Organization", you can state the legal form of the company. This is for information purposes only.Stock corporation (AG in Germany)Limited liability company (GmbH in Germany) + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Legal form' + @sap.quickinfo : 'BP: Legal form of organization' + LegalForm : String(2); + /** First name field for business partners in the Organization category. */ + @sap.label : 'Name 1' + @sap.quickinfo : 'Name 1 of organization' + OrganizationBPName1 : String(40); + /** Second name field for business partners in the Organization category. */ + @sap.label : 'Name 2' + @sap.quickinfo : 'Name 2 of organization' + OrganizationBPName2 : String(40); + /** Third name field for business partners in the Organization category. */ + @sap.label : 'Name 3' + @sap.quickinfo : 'Name 3 of organization' + OrganizationBPName3 : String(40); + /** Fourth name field for business partners in the Organization category. */ + @sap.label : 'Name 4' + @sap.quickinfo : 'Name 4 of organization' + OrganizationBPName4 : String(40); + /** + * Indicates the official registration of a company in the Commercial Register. + * + * If a company is not officially registered in the Commercial Register, it has to use some type of text addition, such as foundation pending, when referring to the legal form. + */ + @sap.display.format : 'Date' + @sap.label : 'Date founded' + @sap.quickinfo : 'Date organization founded' + OrganizationFoundationDate : Date; + /** + * Term for the end of bankruptcy proceedings. + * + * This date also indicates that the company no longer exists. + */ + @sap.display.format : 'Date' + @sap.label : 'Liquidation date' + @sap.quickinfo : 'Liquidation date of organization' + OrganizationLiquidationDate : Date; + /** Denotes the term that you define for a business partner, and via which you can restrict the search for a business partner in the business partner search or in the locator. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Search term 1' + @sap.quickinfo : 'Search term 1 for business partner' + SearchTerm1 : String(20); + /** Denotes the term that you define for a business partner, and via which you can restrict the search for a business partner in the business partner search or in the locator. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Search term 2' + @sap.quickinfo : 'Search term 2 for business partner' + SearchTerm2 : String(20); + @sap.label : 'Other Last Name' + @sap.quickinfo : 'Other Last Name of a Person' + AdditionalLastName : String(40); + @sap.display.format : 'Date' + @sap.label : 'Date of Birth' + @sap.quickinfo : 'Date of Birth of Business Partner' + BirthDate : Date; + @sap.label : 'Birthplace' + @sap.quickinfo : 'Birthplace of business partner' + BusinessPartnerBirthplaceName : String(40); + /** If the business partner is blocked centrally, certain activities cannot be executed. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Central Block' + @sap.quickinfo : 'Central Block for Business Partner' + BusinessPartnerIsBlocked : Boolean; + /** + * You can use the business partner type to group business partners according to your own criteria in Customizing (IMG). + * + * In Customizing you can show or hide fields for data entry, depending on the requirements of the relevant business partner type.Select a business partner type. You can obtain help by pressing the F4 key. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'BP Type' + @sap.quickinfo : 'Business Partner Type' + BusinessPartnerType : String(4); + @sap.creatable : 'false' + @sap.updatable : 'false' + ETag : String(26); + /** First name field for business partners in the Group category. */ + @sap.label : 'Name 1' + @sap.quickinfo : 'Name 1 (group)' + GroupBusinessPartnerName1 : String(40); + /** Second name field for business partners in the Group category. */ + @sap.label : 'Name 2' + @sap.quickinfo : 'Name 2 (group)' + GroupBusinessPartnerName2 : String(40); + /** + * Internal key for identifying the address for communication data that spans all addresses in Business Partner. + * + * For more information on the significance and usage of the address number, see the documentation for Business Address Services (BAS). + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Address Number' + @sap.creatable : 'false' + @sap.updatable : 'false' + IndependentAddressID : String(10); + /** The check digit is derived from a special check digit procedure from digits of the previous international location numbers. In this way, you can check whether the ILN entered is actually valid. */ + @sap.display.format : 'NonNegative' + @sap.label : 'Check digit' + @sap.quickinfo : 'Check digit for the international location number' + InternationalLocationNumber3 : String(1); + @sap.label : 'Middle Name' + @sap.quickinfo : 'Middle Name or Second Forename of a Person' + MiddleName : String(40); + /** + * The name format rule country and the name format rule key together uniquely identify a formatting rule. + * + * A country can have several formats which correspond to different rules. Formatting rules describe the format of a person name. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Country for format' + @sap.quickinfo : 'Country for Name Format Rule' + NameCountry : String(3); + /** See Name format. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Name Format' + @sap.quickinfo : 'Name format' + NameFormat : String(2); + /** + * States the complete name of a person. + * + * The complete name is generally generated and saved by the Business Address Services (BAS) according to country-specific rules from the individual name components (without the form of address).If, during the formatting of an address, you want to use an alternative name, you can manually format the alternative name here. + */ + @sap.label : 'Full Name' + PersonFullName : String(80); + /** + * Internal key for identifying a person in Business Address Services. + * + * For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Person number' + @sap.creatable : 'false' + @sap.updatable : 'false' + PersonNumber : String(10); + /** + * Establishes if the business partner is meant to be archived. + * + * If the indicator is set, the relevant business partner can be archived from the view of the business partner administration.If the check of the data to be archived shows, for example, that there are still active business transactions the archiving of the business partner data is prevented even if the indicator is set.If the indicator is not set, the business partner will not be taken into consideration during archiving. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Archiving Flag' + @sap.quickinfo : 'Central Archiving Flag' + IsMarkedForArchiving : Boolean; + /** + * Business partner number from an external system or a legacy system. + * + * If the current business partner is known under a different number in an external system, you can store this number here for information purposes.Direct input gives you the option of maintaining a business partner by specifying the external business partner number. If you maintain business partner data in your legacy system, you can transmit changes made to business partners to the SAP system without having to know the SAP business partner number in the legacy system. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'External BP Number' + @sap.quickinfo : 'Business Partner Number in External System' + BusinessPartnerIDByExtSystem : String(20); + /** Company ID standard for the whole group. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Trading Partner No.' + @sap.quickinfo : 'Company ID of trading partner' + TradingPartner : String(6); + @cds.ambiguous : 'missing on condition?' + to_BuPaIdentification : Association to many API_BUSINESS_PARTNER.A_BuPaIdentification { }; + @cds.ambiguous : 'missing on condition?' + to_BuPaIndustry : Association to many API_BUSINESS_PARTNER.A_BuPaIndustry { }; + @cds.ambiguous : 'missing on condition?' + to_BusinessPartnerAddress : Association to many API_BUSINESS_PARTNER.A_BusinessPartnerAddress { }; + @cds.ambiguous : 'missing on condition?' + to_BusinessPartnerBank : Association to many API_BUSINESS_PARTNER.A_BusinessPartnerBank { }; + @cds.ambiguous : 'missing on condition?' + to_BusinessPartnerContact : Association to many API_BUSINESS_PARTNER.A_BusinessPartnerContact { }; + @cds.ambiguous : 'missing on condition?' + to_BusinessPartnerRole : Association to many API_BUSINESS_PARTNER.A_BusinessPartnerRole { }; + @cds.ambiguous : 'missing on condition?' + to_BusinessPartnerTax : Association to many API_BUSINESS_PARTNER.A_BusinessPartnerTaxNumber { }; + @cds.ambiguous : 'missing on condition?' + to_Customer : Association to API_BUSINESS_PARTNER.A_Customer { }; + @cds.ambiguous : 'missing on condition?' + to_Supplier : Association to API_BUSINESS_PARTNER.A_Supplier { }; +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Address' +entity API_BUSINESS_PARTNER.A_BusinessPartnerAddress { + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartner : String(10) not null; + /** + * Internal key for identifying a Business Address Services address. + * + * For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Address Number' + key AddressID : String(10) not null; + @odata.Type : 'Edm.DateTimeOffset' + @sap.label : 'Valid From' + @sap.quickinfo : 'Validity Start of a Business Partner Address' + ValidityStartDate : DateTime; + @odata.Type : 'Edm.DateTimeOffset' + @sap.label : 'Valid To' + @sap.quickinfo : 'Validity End of a Business Partner Address' + ValidityEndDate : DateTime; + /** + * You can use authorization groups to stipulate which business partners a user is allowed to process. + * + * Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization Group' + AuthorizationGroup : String(4); + @sap.label : 'GUID of a Business Partner Address' + @sap.heading : '' + @sap.creatable : 'false' + @sap.updatable : 'false' + AddressUUID : UUID; + /** + * Additional address field which is printed above the Street line. + * + * The Street address contains two lines above the street and two lines below the street.See Print the Street address. + */ + @sap.label : 'Street 3' + AdditionalStreetPrefixName : String(40); + /** + * Additional address field which is printed under the Street line. + * + * The Street address has two lines above the street and two lines below the steet.See Print the Street address. + */ + @sap.label : 'Street 5' + AdditionalStreetSuffixName : String(40); + /** + * Time zone as part of an address. + * + * The time zone is automatically determined by the system in address maintenance if time zone Customizing is maintained.It depends on the country and the region. (Region means state, province or county, depending on the country)The automatic determination is only made if there is no value in the time zone field. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Time zone' + @sap.quickinfo : 'Address time zone' + AddressTimeZone : String(6); + /** + * Part of the address (c/o = care of) if the recipient is different from the occupant and the names are not similar (e.g. subtenants). + * + * Put the country-specific code (e.g. c/o) in front of the name of the occupant. This is not automatically done in the print format, like the language-specific word "PO Box".John Smithc/o David BrownThis field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.label : 'c/o' + @sap.quickinfo : 'c/o name' + CareOfName : String(40); + @sap.display.format : 'UpperCase' + @sap.label : 'City Code' + @sap.quickinfo : 'City code for city/street file' + CityCode : String(12); + /** + * City name as part of the address. + * + * The city name is saved redundantly in another database field in upper- case letters, for search help.If the Postal regional structure ('city file') is active, the city name is checked against the Cities defined in the regional structure. + */ + @sap.label : 'City' + CityName : String(40); + /** + * Postal code that is assigned directly to one company (= company postal code = major customer postal code). + * + * This field is used for countries where major companies are assigned their own postal code by the national post office.This postal code has to be entered in the field "Company Postal Code". Postal codes for group major customers, however, have to be entered in the field "PO Box Postal Code", since individual customers with a shared postal code for group major customers are differentiated by means of their PO box. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Company Postal Code' + @sap.quickinfo : 'Company Postal Code (for Large Customers)' + CompanyPostalCode : String(10); + /** + * The country key contains information which the system uses to check entries such as the length of the postal code or bank account number. + * + * The two-character ISO code in accordance with ISO 3166, which is delivered by SAP as a default, is usually used.It could also be the vehicle license plate country-code or a typical country key, for example, in Germany the Federal statistics office key.The country keys are determined at system installation in the global settings.The definition of the country key in the SAP system does not have to match political or government entities.Since the country key does not have to correspond to the ISO code in all installations, programs that differ according to certain values of the country key cannot query the country key T005-LAND1, but have to program based on the ISO code T005 INTCA. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Country Key' + Country : String(3); + /** + * Specifies the county’s name + * + * This field is used to store the county’s name. You can enter the name of the county in this field. + */ + @sap.label : 'County' + County : String(40); + /** + * The delivery service is part of the PO box address. + * + * Some countries offer different services in addition to regular postal delivery and PO boxes, for example the Private Bag or Response Bag. If an address is related to one of these delivery services, the information about this particular delivery service has to be entered in the corresponding fields.In the field "Number of Delivery Service," the number of the Private Bag, Response Bag, or other relevant service has to be entered. Entering a number is not mandatory for each delivery service.For each address, either the information about the PO box or the information about the delivery service can be entered, but not both types of information at the same time.Mr PickeringPrivate Bag 106999Timaru 7942Delivery services will only be taken into account for address formatting in countries in which they are commonly used in addition to regular postal delivery and PO boxes, for example, in Australia, New Zealand, and the USA. In all other countries, these fields will not be taken into account for address formatting. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Delivery Service No.' + @sap.quickinfo : 'Number of Delivery Service' + DeliveryServiceNumber : String(10); + /** + * The delivery service is part of the PO box address. + * + * Some countries offer different services in addition to regular postal delivery and PO boxes, for example the Private Bag or Response Bag. If an address is related to one of these delivery services, the information about this particular delivery service has to be entered in the corresponding fields.In the field "Type of Delivery Service," the type of the delivery service has to be entered.For each address, either the information about the PO box or the information about the delivery service can be entered, but not both types of information at the same time.Mr PickeringPrivate Bag 106999Timaru 7942Delivery services will only be taken into account for address formatting in countries in which they are commonly used in addition to regular postal delivery and PO boxes, for example, in Australia, New Zealand, and the USA. In all other countries, these fields will not be taken into account for address formatting. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Delvry Serv Type' + @sap.quickinfo : 'Type of Delivery Service' + DeliveryServiceTypeCode : String(4); + /** + * City or District supplement + * + * In some countries, this entry is appended with a hyphen to the city name by the automatic address formatting, other countries, it is output on a line of its own or (e.g. in the USA) not printed.See the examples in the Address Layout Key documentation. + */ + @sap.label : 'District' + District : String(40); + /** + * Key for form of address text. + * + * You can also define a form of address text in Customizing.The form of address text can be maintained in different languages. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Title' + @sap.quickinfo : 'Form-of-Address Key' + @sap.creatable : 'false' + @sap.updatable : 'false' + FormOfAddress : String(4); + /** + * This field contains the full name or formatted name of a party. + * + * For organizations or document addresses, typically the fields Name1 and Name2 are concatenated.For persons the field contains the formatted name according to country specific rules. It corresponds e.g. to the content of the fields BUT000-NAME1_TEXT or ADRP-NAME_TEXT. + */ + @sap.label : 'Full Name' + @sap.quickinfo : 'Full name of a party (Bus. Partner, Org. Unit, Doc. address)' + @sap.creatable : 'false' + @sap.updatable : 'false' + FullName : String(80); + /** + * City of residence which is different from the postal city + * + * In some countries, the residential city is required if it differs from the postal city.In the USA, the official street indexes, against which data can be checked, are based on the residential city, not the postal city, which may be different.It is the same in France, where a postally correct address must contain the residential city in a separate line above the postal city, if it differs from the postal city.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.label : 'Different City' + @sap.quickinfo : 'City (different from postal city)' + HomeCityName : String(40); + /** + * House number as part of an address. + * + * It is printed in the Street line.Other supplementary street information can be entered in the House number supplement or one of the Street2, Street3, Street4 or Street5 fields. See Print the Street address.A house number (e.g. 117) or a house number with supplement (e.g. 117a), or a house number range (e.g. 16-20), can be maintained in this field. + */ + @sap.label : 'House Number' + HouseNumber : String(10); + /** + * House number supplement as part of an address, e.g. + * + * App. 17 orSuite 600.It is printed in the Street line.Further Street supplements can be put in one of the fields Street2, Street3, Street4 or Street5.See Print the Street address. + */ + @sap.label : 'Supplement' + @sap.quickinfo : 'House number supplement' + HouseNumberSupplementText : String(10); + /** + * The language key indicates + * + * - the language in which texts are displayed,- the language in which you enter texts,- the language in which the system prints texts. + */ + @sap.label : 'Language Key' + Language : String(2); + /** + * PO Box number as part of an address. + * + * Only enter the PO Box number in this field. The text "PO Box" is provided in the recipient language by the system when you print the address.When you print an address, the "Street address" and the "PO Box address" are distinguished. The print program determines which of them has priority if both are maintained in an address record.Besides the PO Box number, the PO Box address uses the following fields:PO Box postal code, if specified (otherwise the normal postal code)PO Box city, if specified (otherwise the normal city)PO Box region, if specified (otherwise the normal region)PO Box country, if specified (otherwise the normal country)If the address is a "PO Box" (without a number), do not fill the "PO Box" field. Select the "PO Box w/o Number" indicator instead.You can also enter a company postal code for organizational addresses, instead of a PO Box. A separate field is predefined for this entry.For general information and examples about address formatting, see the documentation on the Address Structure Key. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'PO Box' + POBox : String(10); + /** + * Different city for the PO Box as an address component. + * + * The PO Box city can be entered here if it is different from the address city.If the address is only a PO Box address, enter the city in the normal city field.If the address contains two different city names for the address and the PO Box address, use this field. + */ + @sap.label : 'PO Box City' + @sap.quickinfo : 'PO Box city' + POBoxDeviatingCityName : String(40); + /** + * Different PO Box country in address. + * + * The PO Box country can be entered here, if it is different from the street address country.If the address only has a PO Box address, the country is in the normal country field.Use this field if the address has two different country values for the street address and the PO Box address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'PO box country' + POBoxDeviatingCountry : String(3); + /** + * Different Region for PO Box in an address. + * + * Enter the PO Box Region here, if it differs from the street address region.If the address only has a PO Box address, the Region in in the normal Region field.Use this field if the address has two different Region values for the street address and the PO Box address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'PO Box Region' + @sap.quickinfo : 'Region for PO Box (Country, State, Province, ...)' + POBoxDeviatingRegion : String(3); + /** + * PO Box address without PO Box number flag. + * + * Only the word 'PO Box' is output in PO Box addresses without PO Box number.Set this flag for a PO Box address without PO Box number.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'PO Box w/o No.' + @sap.quickinfo : 'Flag: PO Box Without Number' + POBoxIsWithoutNumber : Boolean; + /** + * The PO box lobby is part of the PO box address. + * + * In some countries, entering a PO box, postal code and city is not sufficient to uniquely identify a PO box, because the same PO box number is assigned multiple times in some cities.Therefore, additional information might be required to determine the post office of the PO box in question. This information can be entered in the field "PO Box Lobby."Mr NellingPO Box 4099HighfieldTimaru 7942The PO box lobby will only be taken into account for address formatting in countries in which it is commonly used in addition to regular postal delivery and PO boxes, for example, in Canada or New Zealand. In all other countries, this field will not be taken into account for address formatting. + */ + @sap.label : 'PO Box Lobby' + POBoxLobbyName : String(40); + /** + * Postal code that is required for a unique assignment of the PO box. + * + * This field is used for countries where a different postal code applies to mail that is sent to the PO box rather than to the street address of a particular business partner.Postal codes for group major customers also have to be entered in the field for the PO box postal code since individual customers with a shared postal code for group major customers are differentiated by means of the PO box. Postal codes for major customers (= company postal codes), however, are assigned to one customer only and have to be entered in the field 'Company Postal Code'. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'PO Box Postal Code' + POBoxPostalCode : String(10); + /** + * Internal key for identifying a person in Business Address Services. + * + * For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Person number' + @sap.creatable : 'false' + @sap.updatable : 'false' + Person : String(10); + /** + * Postal code as part of the address + * + * If different postal codes are maintained for the PO Box and Street address of an address, this field contains the Street address postal code. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Postal Code' + @sap.quickinfo : 'City Postal Code' + PostalCode : String(10); + /** + * Communication method with which you can exchange documents and messages with a business partner. + * + * In Business Address Services, you can specify a standard communication method that can be used by programs to determine the means of communication for sending messages.One business partner wants all messages by fax, another by e-mail.The application context can restrict the possible methods of communication. For example, invitations should perhaps only be sent by post because of enclosures, whereas minutes can be sent by post, fax or e-mail.Communication strategies can be defined for this purpose and applied in application contexts. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Comm. Method' + @sap.quickinfo : 'Communication Method (Key) (Business Address Services)' + PrfrdCommMediumType : String(3); + /** + * In some countries, the region forms part of the address. The meaning depends on the country. + * + * The automatic address formatting function prints the region in addresses in the USA, Canada, Italy, Brazil or Australia, and the county in Great Britain.For more information, see the examples in the documentation on the Address Layout Key.Meaning of the regional code in ...Australia -> ProvinceBrazil -> StateCanada -> ProvinceGermany -> StateGreat Britain -> CountyItaly -> ProvinceJapan -> PrefectureSwitzerland -> CantonUSA -> State + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Region' + @sap.quickinfo : 'Region (State, Province, County)' + Region : String(3); + /** + * Street name as part of the address. + * + * The street name is saved, redundantly in upper case in another database field, for search help purposes.There are other fields for address parts which can be printed above or below the street. See Print the Street address.The house number and other supplements are usually maintained in their own fields. See Formatting the Street line. + */ + @sap.label : 'Street' + StreetName : String(60); + /** + * Additional address field which is printed above the Street line. + * + * The Street address contains two lines above the street and two lines below the street.See Print the Street address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.label : 'Street 2' + StreetPrefixName : String(40); + /** + * Additional address field which is printed below the Street line. + * + * The Street address contains two lines above the street and two lines below the street.See Print the Street address. + */ + @sap.label : 'Street 4' + StreetSuffixName : String(40); + /** Specifies the tax jurisdiction. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Jurisdiction' + TaxJurisdiction : String(15); + /** + * Sales and distribution: + * + * Regional zone of Goods recipient.Purchasing:Regional zone of supplier.You can define regional zones to suit the requirements of your own business and country.Sales and distributionthe system automatically proposes a suitable route by using the transportation zone of the goods recipient in combination with other information about the delivery, such as theCountries of origin and destinationShipping conditionsTransportation groupIn the USA, for example, you can define regional zones to correspond to the US postal zip codes. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Transportation Zone' + @sap.quickinfo : 'Transportation zone to or from which the goods are delivered' + TransportZone : String(10); + /** + * Address number from an external system or a legacy system + * + * If the current address has a different number in an external system, you can save this number here for information purposes.In direct input you are able to maintain an address for a business partner by stating the external address number. If your business partner data is maintained in a legacy system, you can thus transmit changes to a BP address to the SAP system without having to know the SAP address number in the legacy system. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'External Address No.' + @sap.quickinfo : 'Address number in external system' + AddressIDByExternalSystem : String(20); + @cds.ambiguous : 'missing on condition?' + to_AddressUsage : Association to many API_BUSINESS_PARTNER.A_BuPaAddressUsage { }; + @cds.ambiguous : 'missing on condition?' + to_EmailAddress : Association to many API_BUSINESS_PARTNER.A_AddressEmailAddress { }; + @cds.ambiguous : 'missing on condition?' + to_FaxNumber : Association to many API_BUSINESS_PARTNER.A_AddressFaxNumber { }; + @cds.ambiguous : 'missing on condition?' + to_MobilePhoneNumber : Association to many API_BUSINESS_PARTNER.A_AddressPhoneNumber { }; + @cds.ambiguous : 'missing on condition?' + to_PhoneNumber : Association to many API_BUSINESS_PARTNER.A_AddressPhoneNumber { }; + @cds.ambiguous : 'missing on condition?' + to_URLAddress : Association to many API_BUSINESS_PARTNER.A_AddressHomePageURL { }; +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Bank' +entity API_BUSINESS_PARTNER.A_BusinessPartnerBank { + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartner : String(10) not null; + /** + * Key identifying a business partner's bank details. + * + * Enter a bank details ID for each separate set of bank details for a business partner.Business Partner: H. MillerBD-ID Fin.institution Acct no. 0001 Chemical Bank, NYC 56234560002 Chemical Bank, NYC 56231220003 First Bank of Pittsburgh ...Business partner: T.Wolsey and Co.BD-ID Fin.institution Acct no.GIR0 Citibank, Charleston ...GIR1 Chemical Bank, NYC ... + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Bank details ID' + key BankIdentification : String(4) not null; + /** + * Identifies the country in which the bank is based. + * + * The country key determines according to which rules the remaining bank data (for example, bank number and bank account number) is checked. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Bank Country' + @sap.quickinfo : 'Bank Country Key' + BankCountryKey : String(3); + /** The name under which the bank operates. */ + @sap.label : 'Bank Name' + @sap.creatable : 'false' + @sap.updatable : 'false' + BankName : String(60); + /** + * The bank key (under which the bank data is stored in the appropriate country) is specified in this field. + * + * The country-specific meaning of this bank key is specified when defining country key.Normally banks have a bank number, which then also appears in the control data of the bank.In certain countries the bank account number assumes this function; in such a case there would be no bank numbers, the bank details are then under the account number.For data medium exchange it can be useful to be able create banks for foreign business partners without a bank number, even if the country in question has bank numbers. In such cases the bank key can be assigned internally.If the bank data is under another key, such as the SWIFT code for example, numbers can also be assigned externally. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Bank Key' + BankNumber : String(15); + /** + * Uniquely identifies a bank throughout the world. + * + * SWIFT stands for Society for Worldwide Interbank Financial Telecommunication.BIC stands for Bank Identifier Code.This globally unique code can be used in international payment transactions to identify the bank without the need to specify an address or bank number. Specification of the SWIFT code/BIC is mainly relevant for automatic payment transactions. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'SWIFT/BIC' + @sap.quickinfo : 'SWIFT/BIC for International Payments' + @sap.creatable : 'false' + @sap.updatable : 'false' + SWIFTCode : String(11); + /** + * Brazil, France, Spain, Portugal and Italy + * + * The field contains a check key for the combination bank number and bank account number.USAIn USA this field is used to differentiate between a savings and a current account (if no value is entered, the default value 01 is used).01 Current account02 Savings account03 Loan account04 General ledgerJapanIn Japan this field specifies the type of account. This information is is copied from the payment medium print program into payment medium. The following is an example of the account types used:01 FUTSU (similar to a savings account)02 TOUZA (similar to a current account)04 CHOCHIKU (similar to an investment account)09 Other types of bank accountsSouth AfricaIn South Africa this field specifies the type of account. The information entered here is forwarded to the bank that carries out the payment order. The following account types are permitted in ABC format:01 Current (Cheque) Account02 Savings Account03 Transmission Account04 Bond Account06 Subscription Share AccountArgentinaIn Argentina this field specifies the type of account:CC Current Account (Cuenta corriente)CA Saving Account (Caja de ahorro)CE Special Saving Account (Caja de ahorro especial)CS Salary Account (Cuenta sueldos)VenezuelaIn Venezuela this field specifies the type of account:CC Checking Account (Cuenta corriente)CA Saving Account (Cuenta de ahorro)CE Special Saving Account (Cuenta de ahorro especial)CS Salary Account (Cuenta sueldos)MexicoIn Mexico this field contains a two-digit key for classifying the bank account (for example, as a savings or current account). This key have different definitions, depending on the bank.NoteFor countries that are not listed here, this field can be used for account-specific information. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Bank Control Key' + BankControlKey : String(2); + /** Here you can enter another name that the payment program can use if the name of the account holder is not the same as the name of the Business Partner. */ + @sap.label : 'Account Holder' + @sap.quickinfo : 'Account Holder Name' + BankAccountHolderName : String(60); + @sap.label : 'Account Name' + @sap.quickinfo : 'Name of Bank Account' + BankAccountName : String(40); + @odata.Type : 'Edm.DateTimeOffset' + @sap.label : 'Valid From' + @sap.quickinfo : 'Validity Start of Business Partner Bank Details' + ValidityStartDate : DateTime; + @odata.Type : 'Edm.DateTimeOffset' + @sap.label : 'Valid To' + @sap.quickinfo : 'Validity End of Business Partner Bank Details' + ValidityEndDate : DateTime; + /** + * A uniform standardized ID number for representing bank details that is in accordance with the ECBS (European Committee for Banking Standards). An IBAN has a maximum of 34 alphanumeric characters and is a combination of the following elements: + * + * Country key of the bank (ISO code)Two-digit check numberCountry-specific account number (in Germany this consists of the bank number and account number, in France the bank number, account number and check key).The IBAN not only makes international payments easier, in some countries it has advantages for domestic payments as well. Depending on the country, it can mean advantages for value and fees.The IBAN can be maintained in parallel with the bank details but does not replace them. It is stored under the master data of the business partner and can then be used when creating the payment medium.Since it is only the bank that has the account that may generate the IBAN corresponding to an account number, the SAP system only generates a proposal. You can confirm or change this proposal. If no proposal is generated, enter the IBAN manually.An IBAN in Belgium may look like this:Electronic Form:BE62510007547061Printed form, as it would appear on an invoice:IBAN BE62 5100 0754 7061 + */ + @sap.display.format : 'UpperCase' + @sap.label : 'IBAN' + @sap.quickinfo : 'IBAN (International Bank Account Number)' + IBAN : String(34); + @sap.display.format : 'Date' + @sap.label : 'IBAN valid from' + @sap.quickinfo : 'Validity start of IBAN' + IBANValidityStartDate : Date; + /** This field contains the number under which the account is managed at the bank. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Bank Account' + @sap.quickinfo : 'Bank Account Number' + BankAccount : String(18); + /** + * Additional details for the bank details of the business partner. + * + * In some countries the data for the bank details of the business partner (bank number, bank account number, name of the account holder) have to supplemented by other details in order to be able to use certain payment processes. This supplementary details are defined here.If additional data is required for the bank details for payment transactions in your country (see the following examples), enter the reference information.If for an automatic debit the bank requires the reference number of the collection authorization in Norway or Great Britain, specify this number here.In Great Britain when making payments to an account in a 'Building Society' you must specify which number payment recipient has. These details must be defined in the reference field, whereas the fields Bank Key and Account Number are to be used for the bank details of the 'Building Society'.In Great Britain when entering a building society account number, the name of the building society should also be maintained in the system. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Reference Details' + @sap.quickinfo : 'Reference Details for Bank Details' + BankAccountReferenceText : String(20); + /** + * States that the bank has collection authorization from the business partner for the account. + * + * Set this indicator if the bank has collection authorization.Note for Accounts Receivable (FI-AR)If this indicator is not set, there is no bank collection.Note for Contract Accounts Receivable and Payable (FI-CA)This indicator is not relevant. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Collect.author.' + @sap.quickinfo : 'Indicator: Collection Authorization' + CollectionAuthInd : Boolean; + /** Name of the city as a part of the address. */ + @sap.label : 'City' + @sap.creatable : 'false' + @sap.updatable : 'false' + CityName : String(35); + /** + * You can use authorization groups to stipulate which business partners a user is allowed to process. + * + * Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization Group' + AuthorizationGroup : String(4); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Contact' +entity API_BUSINESS_PARTNER.A_BusinessPartnerContact { + /** The business partner relationship number is an internal number that identifies the business partner relationship set. */ + @sap.display.format : 'UpperCase' + @sap.label : 'BP Relationship No.' + @sap.quickinfo : 'BP Relationship Number' + key RelationshipNumber : String(12) not null; + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartnerCompany : String(10) not null; + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartnerPerson : String(10) not null; + @sap.display.format : 'Date' + @sap.label : 'Valid To' + @sap.quickinfo : 'Validity Date (Valid To)' + key ValidityEndDate : Date not null; + @sap.display.format : 'Date' + @sap.label : 'Valid From' + @sap.quickinfo : 'Validity Date (Valid From)' + ValidityStartDate : Date; + /** + * States whether the relationship is a standard relationship. + * + * If several relationships of the BP relationship category contact person have been defined for, you can set the indicator standard relationship for one of these relationships.A relationship that is marked as a standard relationship can be used whenA certain scenario automatically selects a contact personThe contact person responsible is not knownYou can give this indicator to only one business partner relationship of a BP relationship category for a particular period. Another relationship of the same relationship category can be indicated as the standard relationship only if the periods for the relationship do not overlap or coincide. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Standard' + @sap.quickinfo : 'Standard Relationship' + IsStandardRelationship : Boolean; + /** + * A relationship may exist between two business partners. The business partner relationship category characterizes the features of the relationship. + * + * A distinction is made between a one-way and an undirected business partner relationship category. In a one-way relationship category, the relationship extends from one partner to another, but not vice versa.Marriage (undirected)Employee (one-way)Contact person (one-way) + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Relationship Cat.' + @sap.quickinfo : 'Business Partner Relationship Category' + RelationshipCategory : String(6); + @cds.ambiguous : 'missing on condition?' + to_ContactAddress : Association to many API_BUSINESS_PARTNER.A_BPContactToAddress { }; + @cds.ambiguous : 'missing on condition?' + to_ContactRelationship : Association to API_BUSINESS_PARTNER.A_BPContactToFuncAndDept { }; +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Role' +entity API_BUSINESS_PARTNER.A_BusinessPartnerRole { + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartner : String(10) not null; + /** + * Function that a business partner takes on, depending on a business transaction. + * + * You can define business partner roles along with their attributes in Customizing.You can create an alphanumeric, 6-digit key for the BP role. You can also choose a title as the short form and a description as the long form for the role text.Screen control in the dialog takes place by assigning a BP view.A program can access specific business partner roles for a business partner using thebusiness partner role category . The role categories are also in the TB003 table. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'BP Role' + key BusinessPartnerRole : String(6) not null; + @odata.Type : 'Edm.DateTimeOffset' + @sap.label : 'Valid From' + @sap.quickinfo : 'Validity Start of a BP Role' + ValidFrom : DateTime; + @odata.Type : 'Edm.DateTimeOffset' + @sap.label : 'Valid To' + @sap.quickinfo : 'Validity End of a BP Role' + ValidTo : DateTime; + /** + * You can use authorization groups to stipulate which business partners a user is allowed to process. + * + * Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization Group' + AuthorizationGroup : String(4); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Tax Number' +entity API_BUSINESS_PARTNER.A_BusinessPartnerTaxNumber { + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartner : String(10) not null; + /** Specifies the tax number category. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number Category' + key BPTaxType : String(4) not null; + /** Specifies the tax number. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax number' + @sap.quickinfo : 'Business Partner Tax Number' + BPTaxNumber : String(20); + /** + * Specifies the tax number. + * + * You can enter up to 60 characters in this field. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number' + @sap.quickinfo : 'Business Partner Tax Number' + BPTaxLongNumber : String(60); + /** + * You can use authorization groups to stipulate which business partners a user is allowed to process. + * + * Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization Group' + AuthorizationGroup : String(4); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.creatable : 'false' +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Customer' +entity API_BUSINESS_PARTNER.A_Customer { + /** Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer' + @sap.quickinfo : 'Customer Number' + key Customer : String(10) not null; + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); + /** + * Indicates if the processing of billing documents is blocked for the customer in all sales areas (company-wide, for example). + * + * You can define different kinds of block, according to the needs of your organization. You can, for example, automatically block the processing of all credit memos to a certain customer, pending manual approval. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Billing Block' + @sap.quickinfo : 'Central Billing Block for Customer' + BillingIsBlockedForCustomer : String(2); + /** Name with which the user who entered the master record was logged on in the R/3 System. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Created by' + @sap.quickinfo : 'Name of Person who Created the Object' + @sap.creatable : 'false' + @sap.updatable : 'false' + CreatedByUser : String(12); + /** Date on which the master record, or the part of the master record being viewed, was created. */ + @sap.display.format : 'Date' + @sap.label : 'Created on' + @sap.quickinfo : 'Date on which the Record Was Created' + @sap.creatable : 'false' + @sap.updatable : 'false' + CreationDate : Date; + /** + * The account group is a classifying feature within customer master records. The account group determines: + * + * in which number range the customer account number should be;whether the number is assigned by the user or by the system;which specifications are necessary or possible in the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account Group' + @sap.quickinfo : 'Customer Account Group' + CustomerAccountGroup : String(4); + /** + * Specifies a classification of the customer (for example, classifies the customer as a bulk purchaser). + * + * The classifications are freely definable according to the needs of your organization. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer Classific.' + @sap.quickinfo : 'Customer Classification' + CustomerClassification : String(2); + @sap.display.format : 'UpperCase' + @sap.label : 'Customer Name' + @sap.quickinfo : 'Customer Full Name' + @sap.creatable : 'false' + @sap.updatable : 'false' + CustomerFullName : String(220); + @sap.label : 'Name of Customer' + @sap.creatable : 'false' + @sap.updatable : 'false' + CustomerName : String(80); + /** + * Indicates if delivery processing is blocked for the customer in all sales areas (company-wide, for example). + * + * You can define different kinds of block, according to the needs of your organization. You can, for example, automatically block all deliveries to a certain customer for credit reasons. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Delivery block' + @sap.quickinfo : 'Central delivery block for the customer' + DeliveryIsBlocked : String(2); + /** + * Denotes a natural person. + * + * In the following countries, the system needs to know whether the taxpayer is a legal or natural person so that it can check the tax numbers correctly:BrazilBulgariaColombiaCroatiaGreeceItalyMexicoPeruSloveniaThailandUkraineThe flag is also used in conjunction with the Statement of Payments to Natural Persons report, as used in the Czech Republic and in Slovakia. This report only covers customers and vendors for whom you have set this indicator.In South Korea, it is used in conjunction with the Generic Withholding Tax Reporting program. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Natural Person' + NFPartnerIsNaturalPerson : String(1); + /** + * Indicates if sales order processing is blocked for the customer in all sales areas (company-wide, for example). + * + * If you block sales order processing, the block counts for the following partner functions of the customer:Sold-to partyShip-to partyPayerIf you want to process an order where the ship-to party differs from the sold-to party, and the ship-to party is blocked, you cannot process the order.You can define different kinds of block, according to the needs of your organization. You can, for example, automatically block all free of charge deliveries and credit memo requests for a certain customer, pending manual approval before further processing can take place. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Order Block' + @sap.quickinfo : 'Central Order Block for Customer' + OrderIsBlockedForCustomer : String(2); + /** + * Indicates that the account is blocked for posting for all company codes. + * + * If you set this indicator, the system prevents users from posting items to this account and issues an error message to inform them that the account is blocked. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Posting Block' + @sap.quickinfo : 'Central Posting Block' + PostingIsBlocked : Boolean; + /** Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Supplier' + @sap.quickinfo : 'Account Number of Supplier' + Supplier : String(10); + /** + * If the customer or the vendor belongs to a group, you can enter a group key here. The group key is freely assignable. + * + * If you create a matchcode using this group key, group evaluations are possible. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Group Key' + CustomerCorporateGroup : String(10); + /** Account number of another master record in which the official address is stored. This address is used, for example, for tax reports to the tax authorities in Italy. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Fiscal address' + @sap.quickinfo : 'Account number of the master record with the fiscal address' + FiscalAddress : String(10); + /** + * An industry is a distinct group of companies with the same basic business activity. The industry key is used in selecting data for evaluations (for example, a vendor master data list). You can specify industries such as trade, banking, service, manufacturing, health care, public service, media and so on. + * + * The industry field belongs to the general data area of customer and vendor master records. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Industry' + @sap.quickinfo : 'Industry key' + @sap.creatable : 'false' + @sap.updatable : 'false' + Industry : String(4); + /** + * Specifies the code that uniquely identifies the industry (or industries) of the customer. + * + * Depending on the standards your organization uses (for example, Standard Industry Codes (SIC)), enter the appropriate code. You can assign more than one industry code to a customer by choosing Create more. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Industry Code 1' + @sap.creatable : 'false' + @sap.updatable : 'false' + IndustryCode1 : String(10); + /** + * Specifies an additional code that identifies the industry (or industries) of the customer. + * + * Depending on the standards your organization uses (for example, Standard Industry Codes (SIC)), enter the appropriate code. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Industry Code 2' + @sap.creatable : 'false' + @sap.updatable : 'false' + IndustryCode2 : String(10); + /** + * Specifies an additional code that identifies the industry (or industries) of the customer. + * + * Depending on the standards your organization uses (for example, Standard Industry Codes (SIC)), enter the appropriate code. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Industry Code 3' + @sap.creatable : 'false' + @sap.updatable : 'false' + IndustryCode3 : String(10); + /** + * Specifies an additional code that identifies the industry (or industries) of the customer. + * + * Depending on the standards your organization uses (for example, Standard Industry Codes (SIC)), enter the appropriate code. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Industry Code 4' + @sap.creatable : 'false' + @sap.updatable : 'false' + IndustryCode4 : String(10); + /** + * Specifies an additional code that identifies the industry (or industries) of the customer. + * + * Depending on the standards your organization uses (for example, Standard Industry Codes (SIC)), enter the appropriate code. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Industry Code 5' + @sap.creatable : 'false' + @sap.updatable : 'false' + IndustryCode5 : String(10); + /** + * Here you enter the first 7 digits of the international location number. + * + * The International Location Number (ILN) is assigned (in Germany by the Centrale for Coorganisation GmbH)) when a company is founded. It consists of 13 digits, the last digit being the check digit. There are two categories of location numbers:Participants who only need an ILN to cleary and unmistakably identify themselves for communication with the business partner are given a category 1 ILN. This cannot be used to identify articles by means of EAN.Participants who wish to assign the location numbers for their own enterprise areas are given a category 2 ILN. For a category 2 ILN, digits 1 to 7 are described as basis number. This is used as basis for the creation of article numbers (EAN). + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Int. location no. 1' + @sap.quickinfo : 'International location number (part 1)' + InternationalLocationNumber1 : String(7); + /** + * Specifies a regional division according to the market categories created by the A. C. Nielsen company. + * + * By allocating a Nielsen division, you can use the services of the Nielsen Institute to create a market analysis of your customers. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Nielsen Indicator' + @sap.quickinfo : 'Nielsen ID' + NielsenRegion : String(2); + /** Classification of companies according to tax aspects. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax type' + ResponsibleType : String(2); + /** + * Specifies the tax number. + * + * Enter the appropriate tax number:Country Tax NumberArgentina CUIT number or CUIL numberBelgium Enterprise numberBrazil CNPJ numberBulgaria Unified identification codeChile RUT numberChina VAT registration number (shui wu deng ji hao)Colombia NIT numberCroatia Legal persons: company identification numberNatural persons: JMBG numberCzech Republic DIC numberFrance SIRET numberGreece Personal IDHungary Tax numberItaly Fiscal codeKazakhstan RNN (obsolete)Mexico RFC numberNetherlands SI registration number (Aansluitnummer UWV) of chain- liability vendorNorway VAT numberPeru RUC numberPhilippines Taxpayer identification number (see below)Poland NIP numberPortugal NIF numberRomania Tax numberRussia INNSlovakia DIC numberSlovenia Tax numberSouth Korea Natural persons: Personal identification numberLegal persons: Corporation IDSpain NIF numberSwitzerland UID numberTaiwan - China GUI registration numberThailand Personal IDTurkey Name of business partner's tax officeUkraine Taxpayer identification numberUnited Kingdom Company registration numberUnited States Social security numberVenezuela RIF numberIn the Philippines, enter the taxpayer identification number with a V or N at the end, as follows:If the business partner is liable to VAT: 999-999-999-999VIf the business partner is not liable to VAT: 999-999-999-999N + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number 1' + @sap.creatable : 'false' + @sap.updatable : 'false' + TaxNumber1 : String(16); + /** + * Specifies the tax number. + * + * Enter the appropriate tax number:Country Tax NumberArgentina NIP number or CM numberBelgium VAT numberBrazil CPF numberBulgaria Legal persons: tax numberNatural persons: personal IDCroatia OIB number Czech Republic ICO numberFrance SIREN numberGreece AFM numberIndia TINItaly VAT numberKazakhstan BC (Beneficiary Code)Netherlands BSN numberRussia OKPO codeSlovakia ICO numberSouth Korea VAT registration numberSweden Organization registration numberSwitzerland VAT numberTaiwan - China Tax registration numberUkraine Legal persons: USREOU numberNatural persons: SRNP numberTurkey Tax numberUnited Kingdom NI numberUnited States Employer identification numberVenezuela NIT number + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number 2' + @sap.creatable : 'false' + @sap.updatable : 'false' + TaxNumber2 : String(11); + /** + * Specifies the tax number. + * + * Enter the tax number that applies:Country Tax numberArgentina Withholding agent numberBrazil State tax numberBulgaria Social security numberMexico CURP numberKazakhstan BINNetherlands Tax registration number (Loonbelastingnummer) of the chain-liability vendorRussia KPP numberThailand Tax ID Ukraine VAT registration number + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number 3' + @sap.creatable : 'false' + @sap.updatable : 'false' + TaxNumber3 : String(18); + /** + * Specifies the tax number. + * + * Enter the appropriate tax number:Country Tax NumberBrazil Municipal tax numberKazakhstan IINRussia OFK number (for public bodies only) + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number 4' + @sap.creatable : 'false' + @sap.updatable : 'false' + TaxNumber4 : String(18); + /** + * Kazakhstan + * + * Specifies the certificate of registration as VAT payer in the following format: XXXXXYYYYYYYZZZZZZZZ, where: XXXXX is the certificate serial number, YYYYYYY is the certificate number and ZZZZZZZZ is the date of certificate issue. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number 5' + @sap.creatable : 'false' + @sap.updatable : 'false' + TaxNumber5 : String(60); + /** + * Taxes in Argentina: + * + * The format and the check of tax number 1 depend on the two-digit tax number type.The tax number type is an identification type for tax in Argentina (for example, 80 for CUIT) and is used for the DGI tax report. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number Type' + TaxNumberType : String(2); + /** + * VAT registration number (VAT reg.no.) of the customer, vendor or your company code. + * + * The VAT registration number is used within the EU for tax-exempt deliveries for the "EC sales list". The check rules are defined for each EU country and cannot be changed. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'VAT Registration No.' + @sap.quickinfo : 'VAT Registration Number' + VATRegistration : String(20); + /** + * Indicates that all data in this master record is to be deleted. + * + * To delete this data, you have to run the archiving program for Accounts Receivable or Payable. This program will archive all master records marked for deletion provided that there is no dependent data in them.Deletion flags can also be used in the program for deleting master data. You should, however, run this program only to delete test data prior to production startup. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Deletion flag' + @sap.quickinfo : 'Central Deletion Flag for Master Record' + DeletionIndicator : Boolean; + @cds.ambiguous : 'missing on condition?' + to_CustomerCompany : Association to many API_BUSINESS_PARTNER.A_CustomerCompany { }; + @cds.ambiguous : 'missing on condition?' + to_CustomerSalesArea : Association to many API_BUSINESS_PARTNER.A_CustomerSalesArea { }; +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Customer Company' +entity API_BUSINESS_PARTNER.A_CustomerCompany { + /** Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer' + @sap.quickinfo : 'Customer Number' + key Customer : String(10) not null; + /** The company code is an organizational unit within financial accounting. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Company Code' + key CompanyCode : String(4) not null; + /** Contains settings that control how the system handles differences between the invoice amount and the amount received from a customer or the amount paid to a supplier. A tolerance group is unique within a company code. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tolerance Group' + @sap.quickinfo : 'Tolerance Group for Business Partner/G/L Account' + APARToleranceGroup : String(4); + /** This field contains the account number the company is listed under at the customer. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account at customer' + @sap.quickinfo : 'Our account number at customer' + AccountByCustomer : String(12); + /** + * Identification code for the accounting clerk. + * + * The name of the accounting clerk defined by this identification code can be used in the payment program for correspondence and reporting (for example, open item lists). + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Clerk Abbrev.' + @sap.quickinfo : 'Accounting Clerk Abbreviation' + AccountingClerk : String(2); + @sap.label : 'Acctg clerk''s fax' + @sap.quickinfo : 'Accounting clerk''s fax number at the customer/vendor' + AccountingClerkFaxNumber : String(31); + @sap.label : 'Clrk''s internet add.' + @sap.quickinfo : 'Internet address of partner company clerk' + AccountingClerkInternetAddress : String(130); + @sap.display.format : 'UpperCase' + @sap.label : 'Acct.clerks tel.no.' + @sap.quickinfo : 'Accounting clerk''s telephone number at business partner' + AccountingClerkPhoneNumber : String(30); + /** + * + * + * Account number of the customer for whom automatic payment transactions are to be carried out.The account number is only needed if bank collections are not to be made via the customer who owes the receivables. The same applies to refunds of payables.The specification in this field only applies to this company code. There is another field in which you can enter an alternative payee for all company codes. If both fields are filled, the specification for the company code has priority. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Alternative payer' + @sap.quickinfo : 'Account number of an alternative payer' + AlternativePayerAccount : String(10); + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); + /** Indicator which specifies at what intervals the collective invoices are to be created for the customer. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Coll.Invoice Variant' + @sap.quickinfo : 'Collective Invoice Variant' + CollectiveInvoiceVariant : String(1); + /** + * Internal memo of the accounting department. + * + * The memo serves only as information on special features of the customer/vendor. + */ + @sap.label : 'Account Memo' + @sap.quickinfo : 'Memo' + CustomerAccountNote : String(30); + /** + * This field contains the account number of the head office. + * + * This account number is only specified for branch accounts. All postings for which the account number of the branch is specified, are automatically posted to the head office account. The account number of the branch affected is noted in the line items.No line items or balances are managed in the branch account. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Head office' + @sap.quickinfo : 'Head office account number (in branch accounts)' + CustomerHeadOffice : String(10); + /** + * Indicates that during automatic payment transactions clearing is made with the corresponding vendor account, and that during manual clearing procedures, the items of that vendor account are also selected. + * + * To use this function in automatic payment transactions, you have toenter the vendor account number in the customer master record,enter the customer account number in the vendor master record, andselect the "Clearing with customer" indicator in the vendor master record.If you set this indicator, the system will also include items of the vendor account in customer dunning. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Clearing with vendor' + @sap.quickinfo : 'Indicator: Clearing between customer and vendor ?' + CustomerSupplierClearingIsUsed : Boolean; + /** All bank data is determined using this key. */ + @sap.display.format : 'UpperCase' + @sap.label : 'House Bank' + @sap.quickinfo : 'Short Key for a House Bank' + HouseBank : String(5); + /** Enter an interest calculation indicator here if the account is to be included in automatic interest calculation. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Interest indicator' + @sap.quickinfo : 'Interest calculation indicator' + InterestCalculationCode : String(2); + /** + * The date in this field displays the last time the interest calculation program processed this account. This is generally the upper limit of the last interest run. + * + * Generally, this date is automatically maintained by the program (batch input). A manual entry in this field should only be made if an error has occurred or when implementing the interest calculation. + */ + @sap.display.format : 'Date' + @sap.label : 'Last Key Date' + @sap.quickinfo : 'Key Date of Last Interest Calculation' + InterestCalculationDate : Date; + /** + * Indicates that payment transactions and dunning notices are created for the branch. + * + * Normally automatic payment transactions and dunning notices are created for the head office.NoteSelect this indicator only if this account is a head office account. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Local Processing' + @sap.quickinfo : 'Indicator: Local Processing?' + IsToBeLocallyProcessed : Boolean; + /** If this indicator is set, every customer/vendor open item is paid separately during automatic payment transactions. This means that open items are not grouped together for payment. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Individual Payment' + @sap.quickinfo : 'Indicator: Pay All Items Separately?' + ItemIsToBePaidSeparately : Boolean; + /** + * Indicates the layout rule for the Allocation field in the document line item. + * + * The system uses a standard sort sequence for displaying line items. Among other things, it sorts the items according to the content of the Allocation field. This field can be filled either manually or automatically (by the system) when a document line item is entered.For this purpose, the system requires rules that determine which information is to be taken from the document header or from the document line item and placed in the field. The rules can be stored in the master record of an account which enables you to determine the standard sort sequence on an account-specific basis.NoteField information from another document line item cannot be adopted into the field of a particular item. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Sort Key' + @sap.quickinfo : 'Key for Sorting According to Assignment Numbers' + LayoutSortingRule : String(3); + /** + * Block key (enqueue key) that is used to block an open item or an account to payment transactions. + * + * You can use the block key as described below.Automatic Payment TransactionsIn automatic payment transactions, the block takes effect when it is entered in the system as follows:In the master recordIn the documentIf you enter the block in the master record then all open items for this account are contained in the exception list.The following block keys have a special meaning in the master record:The block key * has the effect that all items of the account are skipped in automatic payment transactions.The block key + has the effect that all items are skipped in which a payment method was not entered explicitly.The block key A is always set automatically when a down payment is entered. Therefore, you must not delete the block key A or use it for other purposes.Whether a block key can be set or removed in payment proposal processing depends on the attribute Changeable in payment proposal of the block key.Manual PaymentsManual payments are only affected by a block key in the document if you set the attribute Blocked for manual payments in the block key.A block key that was set in the master record does not have any effect on manual payments. You can have the system issue a warning message in that case. To do so, you have to make system settings. Set up message 671 of work area F5 in message control accordingly. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Payment Block' + @sap.quickinfo : 'Block Key for Payment' + PaymentBlockingReason : String(1); + /** + * List of payment methods which may be used in automatic payment transactions with this customer/vendor if you do not specify a payment method in the item to be paid. + * + * If you do specify a particular payment method in the item to be paid, this specification has priority over the specifications in the master record. You may also specify payment methods in the item which are not listed in the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Payment Methods' + @sap.quickinfo : 'List of Respected Payment Methods' + PaymentMethodsList : String(10); + /** + * Key for defining payment terms composed of cash discount percentages and payment periods. + * + * It is used in sales orders, purchase orders, and invoices. Terms of payment provide information for:Cash managementDunning proceduresPayment transactionsData can be entered in the field for the terms of payment key in various ways as you enter a business transaction:In most business transactions, the system defaults the key specified in the master record of the customer/vendor in question.In some transactions (for example, credit memos), however, the system does not default the key from the master record. Despite this, you can use the key from the customer/vendor master record by entering "*" in the field.Regardless of whether or not a key is defaulted from the master record, you can manually enter a key during document entry at:item level in sales ordersheader level in purchase orders and invoicesMaster records have separate areas for Financial Accounting, Sales, and Purchasing. You can specify different terms of payment keys in each of these areas. When you then enter a business transaction, the application in question will use the key specified in its area of the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Terms of Payment' + @sap.quickinfo : 'Terms of Payment Key' + PaymentTerms : String(4); + /** This indicator specifies that the customer/vendor should be sent all payment advice information by EDI. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Pmnt advice by EDI' + @sap.quickinfo : 'Indicator: Send Payment Advices by EDI' + PaytAdviceIsSentbyEDI : Boolean; + /** + * Indicates that the account is blocked for posting in the specified company code. + * + * If you set this indicator, the system prevents users from posting items to this account and issues an error message to inform them that the account is blocked. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Co.code post.block' + @sap.quickinfo : 'Posting block for company code' + PhysicalInventoryBlockInd : Boolean; + /** + * The reconciliation account in G/L accounting is the account which is updated parallel to the subledger account for normal postings (for example, invoice or payment). + * + * For special postings (for example, down payment or bill of exchange), this account is replaced by another account (for example, 'down payments received' instead of 'receivables').The replacement takes place due to the special G/L indicator which you must specify for these types of postings. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Reconciliation Acct' + @sap.quickinfo : 'Reconciliation Account in General Ledger' + ReconciliationAccount : String(10); + /** + * Indicator that the payment history of the customer is to be recorded. + * + * The amount and number of payments are then recorded per calendar month, as well as the average days in arrears.Information about cash discount payments and net payments is recorded separately.The indicator should not be set for one-time accounts and accounts which are paid automatically (bank collection or bank bill in Germany, bill of exchange payment request in France).You can only carry out evaluation of the payment history, for example, with the report for customer evaluation with OI listing, if you have selected this field. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Record Pmnt History' + @sap.quickinfo : 'Indicator: Record Payment History ?' + RecordPaymentHistoryIndicator : Boolean; + /** Name or identification code of the accounting clerk at the customer. */ + @sap.label : 'User at customer' + UserAtCustomer : String(15); + /** + * Indicates that the company code data in this master record is to be deleted. + * + * To delete this data, you have to run the archiving program for Accounts Receivable or Payable. This program will archive all master records marked for deletion provided that there is no dependent data in them.This deletion flag cannot be used in the program that deletes master data. You should, however, run this program only to delete test data prior to production startup. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Co.cde deletion flag' + @sap.quickinfo : 'Deletion Flag for Master Record (Company Code Level)' + DeletionIndicator : Boolean; + /** + * In cash management, customers and vendors are allocated to planning groups by means of an entry made in the master record. + * + * You can define these planning groups in Customizing or the Implementation Guide (you will need to ensure that they are all the same length). In order to improve the liquidity forecast display for major customers and vendors, it can be advisable to enter their account number as the planning group.For the planning groups themselves a naming convention should be set up to improve liquidity forecasting. In the following examples, the customer planning groups begin with an "R" for receipts, and the vendor planning groups begin with an "E" for expenses.R1 Customers paying by bank collectionR2 Other domestic customersR3 Customers abroadR4 Affiliated company customersR5 High risk customersR6 Major customersR7 Rental incomeR8 Repayment of loans...E1 Domestic vendorsE2 Vendors abroadE3 Affiliated company vendorsE4 Major vendorsE5 Personnel costsE6 TaxesE7 Investments... + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Planning Group' + CashPlanningGroup : String(10); + /** With the key specified here, you can refer to known/negotiated leave. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Known/Negotiat.Leave' + @sap.quickinfo : 'Short Key for Known/Negotiated Leave' + KnownOrNegotiatedLeave : String(4); + /** The value adjustment key controls the way the open items are processed during individual value adjustment. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Value Adjustment' + @sap.quickinfo : 'Value Adjustment Key' + ValueAdjustmentKey : String(2); + /** + * The account group is a classifying feature within customer master records. The account group determines: + * + * in which number range the customer account number should be;whether the number is assigned by the user or by the system;which specifications are necessary or possible in the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account Group' + @sap.quickinfo : 'Customer Account Group' + CustomerAccountGroup : String(4); + @cds.ambiguous : 'missing on condition?' + to_CustomerDunning : Association to many API_BUSINESS_PARTNER.A_CustomerDunning { }; + @cds.ambiguous : 'missing on condition?' + to_WithHoldingTax : Association to many API_BUSINESS_PARTNER.A_CustomerWithHoldingTax { }; +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Customer Dunning' +entity API_BUSINESS_PARTNER.A_CustomerDunning { + /** Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer' + @sap.quickinfo : 'Customer Number' + key Customer : String(10) not null; + /** The company code is an organizational unit within financial accounting. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Company Code' + key CompanyCode : String(4) not null; + /** + * The dunning area represents an organizational entity that is responsible for dunning. The dunning areas represent a sub-structure of the company codes. + * + * If different responsibilities or different dunning procedures exist within a company code, you can set up corresponding dunning areas.All dunning notices are made separately according to dunning areas, and if necessary with different dunning procedures.The dunning area must be noted in the line items. As long as documents are copied from preliminary work areas (billing documents), the dunning area can be derived from details such as division or sales area, if necessary. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Dunning Area' + key DunningArea : String(2) not null; + /** Key which reflects the reason for a dunning block indicator. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Dunning Block' + DunningBlock : String(1); + /** + * Number that specifies how often an item or account has been dunned. + * + * The business partner has received the dunning level from the last dunning run.If you use dunning areas, it is the dunning level that the business partner received from the last dunning run in the dunning area assigned.The dunning program sets the dunning level automatically when the customer or vendor receives a dunning notice. + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Dunning Level' + DunningLevel : String(1); + /** This field contains the key for the dunning procedure to be used. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Dunning Procedure' + DunningProcedure : String(4); + /** + * Account number of the customer who is to be the recipient of the dunning letters. + * + * The account number is only needed if dunning letters are not sent to the customer who owes the receivables. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Dunning Recipient' + @sap.quickinfo : 'Account Number of the Dunning Recipient' + DunningRecipient : String(10); + /** Date on which the last dunning notice was made. */ + @sap.display.format : 'Date' + @sap.label : 'Last Dunned' + @sap.quickinfo : 'Date of Last Dunning Notice' + LastDunnedOn : Date; + /** + * Date on which a legal dunning procedure was initiated. + * + * The printing of dunning notices in the legal dunning procedure generates an internal notice about any further account movements. A dunning notice is not created for the customer.If the Legal dunning procedure field in the master record contains a date, this means that the account is involved in a legal dunning procedure. The relationship between this date and the dunning date does not affect how the account is processed.The printing of account movements in the legal dunning procedure differs from the normal printing of dunning notices as follows:You must specify a separate form for your dunning procedure in Customizing. For more information, see Customizing (IMG) under Dunning Forms.The dunning program also displays text element 520 "Legal dunning procedure". This makes it possible to display the date of the legal dunning procedure from the master record.The program also displays the documents blocked for dunning and those with a payment method (automatic debit, bank direct debit).Although dunning notices are printed, the dunning level does not change in the master record or in the items. New dunning level = old dunning level.The program only updates the date of the last dunning run.Enter the date manually. + */ + @sap.display.format : 'Date' + @sap.label : 'Legal Dunn.Proc.From' + @sap.quickinfo : 'Date of the Legal Dunning Proceedings' + LegDunningProcedureOn : Date; + /** + * Identification code for the accounting clerk dealing with dunning letters. + * + * Using this identification code, the accounting clerk whose name is printed on the dunning letters is determined.If this field is not filled, then the entry from the Accounting clerk field is used. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Dunning Clerk' + DunningClerk : String(2); + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); + /** + * The account group is a classifying feature within customer master records. The account group determines: + * + * in which number range the customer account number should be;whether the number is assigned by the user or by the system;which specifications are necessary or possible in the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account Group' + @sap.quickinfo : 'Customer Account Group' + CustomerAccountGroup : String(4); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Sales Area' +entity API_BUSINESS_PARTNER.A_CustomerSalesArea { + /** Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer' + @sap.quickinfo : 'Customer Number' + key Customer : String(10) not null; + /** + * An organizational unit responsible for the sale of certain products or services. The responsibility of a sales organization may include legal liability for products and customer claims. + * + * You can assign any number of distribution channels and divisions to a sales organization. A particular combination of sales organization, distribution channel, and division is known as a sales area. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Sales Organization' + key SalesOrganization : String(4) not null; + /** + * The way in which products or services reach the customer. Typical examples of distribution channels are wholesale, retail, or direct sales. + * + * You can maintain information about customers and materials by sales organization and distribution channel. Within a sales organization you can deliver goods to a given customer through more than one distribution channel.You can assign a distribution channel to one or more sales organizations. If, for example, you have numerous sales organizations, each sales organization may use the "Wholesale" distribution channel.For each combination of sales organization and distribution channel, you can further assign one or more of the divisions that are defined for the sales organization. You can, for example, assign "Food" and "Non-food" divisions to the "Wholesale" distribution channel. A particular combination of sales organization, distribution channel, and division is known as a sales area. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Distribution Channel' + key DistributionChannel : String(2) not null; + /** + * A way of grouping materials, products, or services. The system uses divisions to determine the sales areas and the business areas for a material, product, or service. + * + * A product or service is always assigned to just one division. From the point of view of sales and distribution, the use of divisions lets you organize your sales structure around groups of similar products or product lines. This allows the people in a division who process orders and service customers to specialize within a manageable area of expertise.If a sales organization sells food and non-food products through both retail and wholesaledistribution channels each distribution channel could then be further split into food and non-food divisions. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Division' + key Division : String(2) not null; + /** This field contains the account number your company is listed under at the customer or vendor. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account at customer' + @sap.quickinfo : 'Shipper''s (Our) Account Number at the Customer or Vendor' + AccountByCustomer : String(12); + /** + * The authorization group enables you protect access to certain objects. + * + * In order to carry out a specific activity, the user must have authorization for the combination of the activity and the authorization group. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization Group' + AuthorizationGroup : String(4); + /** + * Indicates if further billing activities are blocked for the customer. The block applies throughout the specified sales area. + * + * If you enter a blocking indicator, billing that is already underway is continued. However, you cannot process the document further.Enter one of the values predefined for your system. If you want to block billing for a customer throughout an entire sales organization, you must enter a blocking indicator for each sales area in which the sales organization is defined.You can block billing for a customer if, for example, there are credit-related or legal problems to be resolved. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'BBlock for SlsA' + @sap.quickinfo : 'Billing block for customer (sales and distribution)' + BillingIsBlockedForCustomer : String(2); + /** Indicates whether a sales order must be delivered completely in a single delivery or whether the order can be partially delivered and completed over a number of deliveries. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Complete Delivery' + @sap.quickinfo : 'Complete Delivery Defined for Each Sales Order?' + CompleteDeliveryIsDefined : Boolean; + /** Customer's currency for a sales area. This currency will be used to settle the customer's charges for the given sales organization. */ + @sap.label : 'Currency' + @sap.semantics : 'currency-code' + Currency : String(5); + @sap.display.format : 'UpperCase' + @sap.label : 'ABC classification' + @sap.quickinfo : 'Customer classification (ABC analysis)' + CustomerABCClassification : String(2); + /** + * The account assignment group to which the system automatically posts the sales document. + * + * The system uses the account assignment group as one of the criteria during the automatic determination of revenue accounts.The system automatically proposes the account assignment group from the customer master record of the payer. You can change the default value in the sales document or the billing document. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Acct Assmt Grp Cust.' + @sap.quickinfo : 'Account Assignment Group for this customer' + CustomerAccountAssignmentGroup : String(2); + /** Identifies a particular group of customers (for example, wholesale or retail) for the purpose of pricing or generating statistics. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer Group' + CustomerGroup : String(2); + /** + * Key for defining payment terms composed of cash discount percentages and payment periods. + * + * It is used in sales orders, purchase orders, and invoices. Terms of payment provide information for:Cash managementDunning proceduresPayment transactionsData can be entered in the field for the terms of payment key in various ways as you enter a business transaction:In most business transactions, the system defaults the key specified in the master record of the customer/vendor in question.In some transactions (for example, credit memos), however, the system does not default the key from the master record. Despite this, you can use the key from the customer/vendor master record by entering "*" in the field.Regardless of whether or not a key is defaulted from the master record, you can manually enter a key during document entry at:item level in sales ordersheader level in purchase orders and invoicesMaster records have separate areas for Financial Accounting, Sales, and Purchasing. You can specify different terms of payment keys in each of these areas. When you then enter a business transaction, the application in question will use the key specified in its area of the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Terms of Payment' + @sap.quickinfo : 'Terms of Payment Key' + CustomerPaymentTerms : String(4); + /** + * A grouping of customers who share the same pricing requirements. + * + * You can define price groups according to the needs of your organization and create pricing records for each group. You can, for example, define a group of customers to whom you want to give the same kind of discount. You can assign a price group to an individual customer either in the customer master record or in the sales document.The system can propose the price group from the customer master record. You can change the proposed value manually in the sales document at both header and item level. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer Price Group' + CustomerPriceGroup : String(2); + /** + * Determines which pricing procedure the system should apply when you create a sales document for the customer. + * + * You can define different pricing procedures for your system. A pricing procedure determines the type and sequence of conditions that the system uses for pricing in, for example, a sales order. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Cust.Pric.Procedure' + @sap.quickinfo : 'Customer Classification for Pricing Procedure Determination' + CustomerPricingProcedure : String(2); + /** + * Indicates if further delivery processing is blocked for the customer. The block applies throughout the specified sales area. + * + * If you enter a blocking indicator, delivery processing that is already underway is continued. However, no new processing can take place.Enter one of the values predefined for your system. If you want to block delivery processing for a customer within a particular sales organization, you must enter a blocking indicator for each sales area in which the sales organization is defined.You can block delivery processing for a customer if, for example, there are credit-related or legal problems to be resolved. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'DelBlckSalesAr.' + @sap.quickinfo : 'Customer delivery block (sales area)' + DeliveryIsBlockedForCustomer : String(2); + /** + * The delivery priority assigned to an item. + * + * You can assign delivery priority to either a particular material or to a combination of customer and material. When you process deliveries collectively, you can use delivery priority as one of the selection criteria. + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Delivery Priority' + DeliveryPriority : String(2); + /** + * Commonly used trading terms that comply with the standards established by the International Chamber of Commerce (ICC). + * + * Incoterms specify internationally recognized procedures that the shipper and the receiving party must follow for the shipping transaction to be completed successfully.If goods are shipped through a port of departure, the appropriate Incoterm might be: FOB ("Free On Board"). You can provide further details (for example, the name of the port) in the secondary Incoterm field: FOB Boston, for example. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Incoterms' + @sap.quickinfo : 'Incoterms (Part 1)' + IncotermsClassification : String(3); + /** + * Provides additional information for the Incoterms. This field is only available for C-Clauses (if customized appropriately). Note the following for the incoterms versions below: + * + * No Version:This field is disabledIncoterm Version 2000This field is disabled as part of standard delivery unless a customer decides to enable it by the way of Customizing for Sales and Distribution under Master Data -> Business Partners -> Customers -> Billing Document -> Incoterms -> Map Incoterms to Versions.Incoterm Version 2010For this version, the field represents:Sea and inland waterway transport - Port of DestinationAny mode of transport - Place of Destination2010 Incoterms are divided as follows:Group 1: Rules for any mode or modes of transport (including by vessel)Incoterms Incoterms Description Location 2CPT Carriage Paid To Place of DestinationCIP Carriage & Insurance Paid To Place of DestinationGroup 2: Rules for sea and inland waterwaysIncoterms Incoterms Description Location 2CFR Cost & Freight Port of DestinationCIF Cost Insurance & Freight Port of Destination + */ + @sap.label : 'Incoterms Location 2' + IncotermsLocation2 : String(70); + /** An incoterms version is an edition containing a list of international terms for transportation that is defined by the International Chamber of Commerce (ICC). */ + @sap.display.format : 'UpperCase' + @sap.label : 'Incoterms Version' + IncotermsVersion : String(4); + /** + * Provides additional information for the primary Incoterm. For Incoterms 2010, this field represents: + * + * 1. For sea and inland waterway transport - Port of Shipment2. For any mode of transport - Place of Delivery 2010Incoterms are divided as follows:Group 1: Rules for any mode or modes of transport (including by vessel)Incoterms Incoterms Description Location 1 EXW Ex Works Place of DeliveryFCA Free Carrier Place of DeliveryCPT Carriage Paid To Place of DestinationCIP Carriage & Insurance Paid To Place of DestinationDAF Delivered at Frontier Place of DeliveryDDP Delivered Duty Paid Place of DestinationDDU Delivered Duty Unpaid Place of DestinationGroup 2: Rules for sea and inland waterwaysIncoterms Incoterms Description Location 1 FAS Free Alongside Ship Port of ShipmentFOB Free On Board Port of ShipmentCFR Cost & Freight Port of DestinationCIF Cost Insurance & Freight Port of DestinationDEQ Delivered Eq Quay (Duty Paid) Port of DestinationDES Delivered Ex Ship Port of DestinationIf the primary incoterm is specified as FOB “Free on Board”, the second field provides details of the port from which the delivery leaves, such as FOB Boston. + */ + @sap.label : 'Incoterms Location 1' + IncotermsLocation1 : String(70); + /** Indicates that all data in the master record will be deleted for the specified sales area. Before the deletion is made, the system checks for dependent data that would prevent the deletion. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Del.ID SlsArea' + @sap.quickinfo : 'Deletion flag for customer (sales level)' + DeletionIndicator : Boolean; + /** + * Additional information for the primary Incoterm. + * + * If the primary Incoterm is, for example, FOB ("Free on Board"), then the second field provides details of the port from which the delivery leaves (for example, "FOB Boston"). + */ + @sap.label : 'Incoterms (Part 2)' + IncotermsTransferLocation : String(28); + /** + * Identifies the calendar that determines the schedule of billing dates for the customer. + * + * If, for example, a customer wants to consolidate the invoices you send out, you can predefine the billing schedule in a calendar in the system. During billing, the system automatically proposes the appropriate billing date from the calendar.The system proposes the billing schedule from the customer master record of the payer. You can change the value manually in the sales document. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Invoicing Dates' + @sap.quickinfo : 'Invoice Dates (Calendar Identification)' + InvoiceDate : String(2); + /** + * The probability (expressed as a percentage) of the customer confirming the inquiry or quotation item as part of a sales order. + * + * The system combines the probability factors from the sales document type and from the customer master record of the sold-to party.If probability is 80% for the sales document type and 50% in the customer master record, the system combines the two values. In this case, the system takes 50% of 80% and proposes 40% for the item.The system proposes the probability. You can change the value manually for the item.You can generate requirements from quotations. Accordingly, the probability of quotation items affects how requirements are passed on. For example, a quotation for 100 pieces and a probability of 50% will generate requirements for 50 pieces. + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Order Probability' + @sap.quickinfo : 'Order Probability of the Item' + ItemOrderProbabilityInPercent : String(3); + /** + * Indicates whether you are allowed to combine orders during delivery processing. + * + * The system proposes the indicator from the customer master record. You can change the value manually in the sales document at both header and item level. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Order Combination' + @sap.quickinfo : 'Order Combination Indicator' + OrderCombinationIsAllowed : Boolean; + /** + * Indicates if further sales order processing is blocked for the customer. The block applies throughout the specified sales area. + * + * You can define blocks according to the needs of your organization. If you enter a blocking indicator, sales order processing that is already underway is continued. However, no new processing can occur.Enter one of the values predefined for your system. If you want to block sales order processing for a customer within a particular sales organization, you must enter a blocking indicator for each sales area in which the sale organization is defined.You can block sales order processing for a customer if, for example, there are credit-related or legal problems to be resolved. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Ord.blk:sls ar.' + @sap.quickinfo : 'Customer order block (sales area)' + OrderIsBlockedForCustomer : String(2); + /** + * Specifies whether the customer requires full or partial delivery for the item. + * + * You use this field to control partial deliveries at the item level. If the customer allows partial delivery, you can choose from different partial delivery options. For example, you can specify whether the customer allows you to make one delivery attempt only on the requested delivery date or whether unlimited delivery attempts are possible.When partial delivery indicator 'D' is set, the order can never have status 'fully delivered'. You must complete each item by entering a reason for rejection. This could be applied to scheduling agreements, for example.You can enter a value in this field only if the customer allows partial deliveries for the entire sales document. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Partial Deliv./Item' + @sap.quickinfo : 'Partial Delivery at Item Level' + PartialDeliveryIsAllowed : String(1); + /** + * Identifies a price list or other condition type (for example, a surcharge or discount). + * + * You can define price list types according to the needs of your own organization. Price list types can be grouped according to:the kind of price list (for example, wholesale or retail)the currency in which the price appearsthe number of the price list typeYou can use price list types to apply conditions during pricing or to generate statistics.In the customer master record, enter one of the values predefined for your system. The system proposes the value automatically during sales order processing. You can change the value manually in the sales document header. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Price List Type' + PriceListType : String(2); + /** + * A group of sales people who are responsible for processing sales of certain products or services. + * + * By using sales groups you can designate different areas of responsibility within a sales office. When you generate sales statistics, you can use the sales group as one of the selection criteria.If sales office personnel service both retail and wholesale markets, you can assign a sales group to each market.You assign each salesperson to a sales group in his or her user master record. You assign each customer to a particular sales group in the customer's master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Sales Group' + SalesGroup : String(3); + /** + * A physical location (for example, a branch office) that has responsibility for the sale of certain products or services within a given geographical area. + * + * When you create sales statistics, you can use a sales office as one of the selection criteria. When you print out order confirmations, you can include the address of the sales office.You can assign each customer to a sales office in the customer master record.Within a sales office you can establish sales groups (for example, departments) with specific sales responsibilities. Each person who works in the sales office can be assigned to a sales group in his or her user master record. Each customer can also be assigned to a particular sales group in the customer master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Sales Office' + SalesOffice : String(4); + /** + * General shipping strategy for the delivery of goods from the vendor to the customer. + * + * You can define shipping conditions in your system which correspond to the requirements of your company. You can specify a shipping condition in the customer master and in the vendor master.Shipping point determination (outbound delivery):The loading group, the plant and the shipping condition determine the shipping point that will be proposed by the system.Route determination (outbound delivery):Apart from the country and the geographical region of the shipping point, the ship-to party and the transportation group, the shipping condition determines the route that the system proposes in the order for the delivery of the goods. In the delivery, the route proposal also takes the weight group into account.A particular customer always requires immediate delivery. You enter the appropriate shipping condition into the customer master record. This means that when you process orders for this customer, the system automatically proposes the express mail room as a shipping point and the quickest way to the airport as a route.If a shipping condition has been assigned to a sales document type in Customizing, this condition will be proposed by the system in the corresponding sales document. If there is no assignment, the system copies the relevant data from the corresponding customer master record of the sold-to party. You cannot change this value during delivery processing. The shipping condition will not be copied from the delivery into the shipment. The shipping condition is one of several criteria for selecting deliveries when you create a shipment. You can enter a shipping condition manually in the shipment where it only serves as a characteristic for grouping shipments. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Shipping Conditions' + ShippingCondition : String(2); + /** + * Plant from which the goods should be delivered to the customer. + * + * This plant is automatically copied into the sales order item as the default value.If there is no default value when you process the sales order item, enter a delivering plant.The value proposed in the item is eitherfrom the customer master record of the goods recipient, orfrom the material master recordThe system checks whether it can propose a value (and for your own plants, whether the material has been created in the plant). If the system can propose a value, the plant is copied to the sales order item where you can change it as required. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Delivering Plant' + @sap.quickinfo : 'Delivering Plant (Own or External)' + SupplyingPlant : String(4); + /** + * A geographical sales district or region. + * + * Each customer can be assigned to a sales district. You can use sales districts to apply pricing conditions. When you want to generate sales statistics, you can use sales districts as a selection criteria.The system can propose a value from the customer master record of the sold-to party. You can change the value manually in the document at the header or item level. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Sales District' + SalesDistrict : String(6); + /** + * Identifies the customer's factory calendar that is used during the processing of invoice lists. + * + * An invoice list is a list of invoices (single or collective) that you create for the customer either periodically or on predefined dates. The periods and dates are defined in the customer's factory calendar. Typically, the recipient of an invoice list takes on the responsibility for collecting payments from numerous individual customers and receives a factoring or del credere discount for the service.If you want to create invoice lists for the customer, you must enter an identifier for a predefined factory calendar. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Invoice List Sched.' + @sap.quickinfo : 'Invoice List Schedule (calendar identification)' + InvoiceListSchedule : String(2); + /** + * Key representing a type of exchange rate in the system. + * + * You enter the exchange rate type to store different exchange rates.You can use the exchange rate type to define a buying rate, selling rate, or average rate for translating foreign currency amounts. You can use the average rate for the currency translation, and the bank buying and selling rates for valuation of foreign currency amounts. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Exchange Rate Type' + ExchangeRateType : String(4); + /** + * Specifies a customer-defined group of customers. + * + * You can define up to five different groups of customers, according to the needs of your organization. You specify the groups in the customer master record under "Additional data". If you assign a particular customer to one or more groups, the system automatically displays the groups in the header data of corresponding sales orders.You can define customer groups in Tables TVV1 through TVV5 and assign them to specific languages in Tables TVV1T through TVV5T. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer Group 1' + @sap.quickinfo : 'Customer group 1' + AdditionalCustomerGroup1 : String(3); + /** + * Specifies a customer-defined group of customers. + * + * You can define up to five different groups of customers, according to the needs of your organization. You specify the groups in the customer master record under "Additional data". If you assign a particular customer to one or more groups, the system automatically displays the groups in the header data of corresponding sales orders.You can define customer groups in Tables TVV1 through TVV5 and assign them to specific languages in Tables TVV1T through TVV5T. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer Group 2' + @sap.quickinfo : 'Customer group 2' + AdditionalCustomerGroup2 : String(3); + /** + * Specifies a customer-defined group of customers. + * + * You can define up to five different groups of customers, according to the needs of your organization. You specify the groups in the customer master record under "Additional data". If you assign a particular customer to one or more groups, the system automatically displays the groups in the header data of corresponding sales orders.You can define customer groups in Tables TVV1 through TVV5 and assign them to specific languages in Tables TVV1T through TVV5T. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer Group 3' + @sap.quickinfo : 'Customer group 3' + AdditionalCustomerGroup3 : String(3); + /** + * Specifies a customer-defined group of customers. + * + * You can define up to five different groups of customers, according to the needs of your organization. You specify the groups in the customer master record under "Additional data". If you assign a particular customer to one or more groups, the system automatically displays the groups in the header data of corresponding sales orders.You can define customer groups in Tables TVV1 through TVV5 and assign them to specific languages in Tables TVV1T through TVV5T. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer Group 4' + @sap.quickinfo : 'Customer group 4' + AdditionalCustomerGroup4 : String(3); + /** + * Specifies a customer-defined group of customers. + * + * You can define up to five different groups of customers, according to the needs of your organization. You specify the groups in the customer master record under "Additional data". If you assign a particular customer to one or more groups, the system automatically displays the groups in the header data of corresponding sales orders.You can define customer groups in Tables TVV1 through TVV5 and assign them to specific languages in Tables TVV1T through TVV5T. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer Group 5' + @sap.quickinfo : 'Customer group 5' + AdditionalCustomerGroup5 : String(3); + /** + * This key identifies the customer payment guarantee procedure. + * + * The customer payment guarantee procedure determines which payment guarantee procedure the system automatically uses when you create a sales document for the customer.In receivables risk management, the system determines the payment guarantee procedure taking into account:the key for the document payment guarantee procedure in the header for the sales document type.the customer payment guarantee procedure key in the customer master.You can define different payment guarantee procedures for your system. The payment guarantee procedure defines the type and sequence of forms of payment guarantee that the system assigns to the sales document items. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Paymt guarant. proc.' + @sap.quickinfo : 'Customer payment guarantee procedure' + PaymentGuaranteeProcedure : String(4); + /** + * The account group is a classifying feature within customer master records. The account group determines: + * + * in which number range the customer account number should be;whether the number is assigned by the user or by the system;which specifications are necessary or possible in the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account Group' + @sap.quickinfo : 'Customer Account Group' + CustomerAccountGroup : String(4); + @cds.ambiguous : 'missing on condition?' + to_PartnerFunction : Association to many API_BUSINESS_PARTNER.A_CustSalesPartnerFunc { }; + @cds.ambiguous : 'missing on condition?' + to_SalesAreaTax : Association to many API_BUSINESS_PARTNER.A_CustomerSalesAreaTax { }; +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Sales Area Tax' +entity API_BUSINESS_PARTNER.A_CustomerSalesAreaTax { + /** Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer' + @sap.quickinfo : 'Customer Number' + key Customer : String(10) not null; + /** + * An organizational unit responsible for the sale of certain products or services. The responsibility of a sales organization may include legal liability for products and customer claims. + * + * You can assign any number of distribution channels and divisions to a sales organization. A particular combination of sales organization, distribution channel, and division is known as a sales area. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Sales Organization' + key SalesOrganization : String(4) not null; + /** + * Specifies a distribution channel that you want to use as a reference for customer and material master data for other distribution channels. + * + * You can specify one distribution channel as the source of customer and material master data for other distribution channels. You need then only to maintain the data in one place.Distrib.channel Ref.distrib.channel01 0102 0103 0104 04In this example, only distribution channels 01 and 04 have customer and material master data defined. Distribution channels 01, 02, and 03 share the master data that you defined for distribution channel 01. Distribution channel 04 has its own master data. When you create a sales order in distribution channel 03, the system checks the customer and material master data against the data defined for distribution channel 01. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'RefDistCh-Cust/Mat.' + @sap.quickinfo : 'Reference distrib.channel for cust.and material masters' + key DistributionChannel : String(2) not null; + /** + * A way of grouping materials, products, or services. The system uses divisions to determine the sales areas and the business areas for a material, product, or service. + * + * A product or service is always assigned to just one division. From the point of view of sales and distribution, the use of divisions lets you organize your sales structure around groups of similar products or product lines. This allows the people in a division who process orders and service customers to specialize within a manageable area of expertise.If a sales organization sells food and non-food products through both retail and wholesaledistribution channels each distribution channel could then be further split into food and non-food divisions. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Division' + key Division : String(2) not null; + /** + * Identifies the country in which the delivery originates. + * + * You can define the country key in a table. As a rule, it is a good idea to use the existing international standards for identifying vehicles from different countries (for example: USA = United States, I = Italy, and so on). The system uses the key tohelp determine the relevant taxes during pricingdetermine important country-specific standards (the length of postal codes and bank account numbers, for example) + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Country' + @sap.quickinfo : 'Departure country (country from which the goods are sent)' + key DepartureCountry : String(3) not null; + /** + * Identifies the condition that the system uses to automatically determine country-specific taxes during pricing. + * + * You can define one or more tax categories for each country. During sales order processing, the system applies the tax category according tothe geographical location of your delivering plant and the location of the customer receiving the goodstax classifications in the customer master record and the material master record.In the USA, for example, you can define tax categories for Federal Sales Tax and Federal Excise Tax. In the U.K., you can define a tax category for Value Added Tax (VAT). + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Category' + @sap.quickinfo : 'Tax category (sales tax, federal sales tax,...)' + key CustomerTaxCategory : String(4) not null; + /** + * Specifies the tax liability of the customer, based on the tax structure of the customer's country. + * + * You can use the tax classification to specify, for example, whether a customer is liable for sales taxes, such as VAT or state sales taxes.During sales order processing, the system copies the tax classification from the tax information stored in thecustomer master record of the payer, if the payer is different from the sold-to party and the sales tax identification number is maintained for the payer.ship to party, if the sales tax identification number of the ship-to party is maintained.sold-to party, if none of the criteria for the payer or the ship-to party are met.During pricing, the system calculates any relevant taxes by taking the following factors into account:The tax classification of the customer and the materialThe country keys of the customer and the delivering plant + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Classification' + @sap.quickinfo : 'Tax classification for customer' + CustomerTaxClassification : String(1); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Withholding Tax' +entity API_BUSINESS_PARTNER.A_CustomerWithHoldingTax { + /** Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer' + @sap.quickinfo : 'Customer Number' + key Customer : String(10) not null; + /** The company code is an organizational unit within financial accounting. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Company Code' + key CompanyCode : String(4) not null; + /** + * This indicator is used to classify the different types of withholding tax. + * + * Withholding tax types classify particular features of a withholding tax including:The time at which the withholding tax is postedThe basis on which the base amount is calculatedThe basis for accumulation (if applicable)Withholding tax types are to be distinguished from withholding tax codes, to which are allocated the withholding tax percentage rate example.Whether a withholding tax can be defined as an existing type by means of a new code, or if a new type needs to be defined will depend on the type of transaction (see below).Note that a business transaction can only be assigned one withholding tax code per withholding tax type. If the business transaction is subject to several withholding taxes simultaneously, these must be represented by different types.This is the case in Argentina for example, where up to four kinds of withholding tax per business transaction are possible. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Withholding Tax Type' + @sap.quickinfo : 'Indicator for Withholding Tax Type' + key WithholdingTaxType : String(2) not null; + /** + * One or more "withholding tax codes" are assigned to each withholding tax type. One of the things these codes determine is the various percentage rates for the withholding tax type. + * + * Note that when processing a business transaction, no more than one withholding tax code can be assigned per withholding tax type. If the business transaction is subject to more than one withholding taxes, these must be represented in the system by defining various withholding tax types. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'W/Tax Code' + @sap.quickinfo : 'Withholding Tax Code' + WithholdingTaxCode : String(2); + @sap.display.format : 'UpperCase' + @sap.label : 'WTax Agent' + @sap.quickinfo : 'Indicator: Withholding Tax Agent?' + WithholdingTaxAgent : Boolean; + /** + * Date from which: + * + * The company code is obligated to withhold tax for the given withholding tax type.This date must be entered in Customizing under the withholding tax information for the company code.The customer is obligated to withhold tax for the withholding tax type.This date must be defined in the customer master record. + */ + @sap.display.format : 'Date' + @sap.label : 'W/Tax Obligated Frm' + @sap.quickinfo : 'Obligated to Withhold Tax From' + ObligationDateBegin : Date; + /** + * Date to which: + * + * The company code is obligated to withhold tax for the withholding tax type.This date must be entered in Customizing under the withholding tax information for the company code.The customer is obigated to withhold tax for the withholding tax type. + */ + @sap.display.format : 'Date' + @sap.label : 'Oblig.to W/Tax Until' + @sap.quickinfo : 'Obligated to Withhold Tax Until' + ObligationDateEnd : Date; + /** + * This is a number issued by the tax authorities per withholding tax type. + * + * This number must be specified in Customizing either:(a) As part of the withholding tax information defined for the company code, or(b) As part of the withholding tax information defined in the customer or vendor master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'W/tax number' + @sap.quickinfo : 'Withholding tax identification number' + WithholdingTaxNumber : String(16); + /** + * Numbered assigned by the relevant authorities for exemption from withholding tax. + * + * This number must be entered in the system as follows:In the vendor master record in the case of vendorsFor customers, in Customizing under the settings for withholding tax information for the company code per withholding tax type. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Exemption Number' + @sap.quickinfo : 'Exemption Certificate Number' + WithholdingTaxCertificate : String(25); + /** + * Rate of exemption from withholding tax. + * + * Those persons/activities subject to withholding tax can be exempted from withholding tax up to the percentage rate you enter here. This exemption rate refers to the withholding tax amount itself and not to the whole amount liable to withholding tax (withholding tax base amount).The gross amount of an invoice is 100.00 and the withholding tax base amount is defined as gross. The withholding tax rate is 10% meaning that the withholding tax amount is 10.00. Given an exemption rate of 30%, the withholding tax amount is reduced to 7.00. + */ + @sap.label : 'Exemption Rate' + WithholdingTaxExmptPercent : Decimal(5, 2); + /** Date from which withholding tax exemption applies. */ + @sap.display.format : 'Date' + @sap.label : 'Exemption Start Date' + @sap.quickinfo : 'Date on Which Exemption Begins' + ExemptionDateBegin : Date; + /** Date on which withholding tax exemption expires. */ + @sap.display.format : 'Date' + @sap.label : 'Exemption End Date' + @sap.quickinfo : 'Date on Which Exemption Ends' + ExemptionDateEnd : Date; + /** + * Indicator used to classify different types of exemption from liability to a particular withholding tax. + * + * These indicators can be defined per withholding tax type in the vendor master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Exemption Reason' + @sap.quickinfo : 'Reason for Exemption' + ExemptionReason : String(2); + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Sales Partner Functions' +entity API_BUSINESS_PARTNER.A_CustSalesPartnerFunc { + /** Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer' + @sap.quickinfo : 'Customer Number' + key Customer : String(10) not null; + /** + * An organizational unit responsible for the sale of certain products or services. The responsibility of a sales organization may include legal liability for products and customer claims. + * + * You can assign any number of distribution channels and divisions to a sales organization. A particular combination of sales organization, distribution channel, and division is known as a sales area. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Sales Organization' + key SalesOrganization : String(4) not null; + /** + * The way in which products or services reach the customer. Typical examples of distribution channels are wholesale, retail, or direct sales. + * + * You can maintain information about customers and materials by sales organization and distribution channel. Within a sales organization you can deliver goods to a given customer through more than one distribution channel.You can assign a distribution channel to one or more sales organizations. If, for example, you have numerous sales organizations, each sales organization may use the "Wholesale" distribution channel.For each combination of sales organization and distribution channel, you can further assign one or more of the divisions that are defined for the sales organization. You can, for example, assign "Food" and "Non-food" divisions to the "Wholesale" distribution channel. A particular combination of sales organization, distribution channel, and division is known as a sales area. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Distribution Channel' + key DistributionChannel : String(2) not null; + /** + * A way of grouping materials, products, or services. The system uses divisions to determine the sales areas and the business areas for a material, product, or service. + * + * A product or service is always assigned to just one division. From the point of view of sales and distribution, the use of divisions lets you organize your sales structure around groups of similar products or product lines. This allows the people in a division who process orders and service customers to specialize within a manageable area of expertise.If a sales organization sells food and non-food products through both retail and wholesaledistribution channels each distribution channel could then be further split into food and non-food divisions. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Division' + key Division : String(2) not null; + /** + * The sequential number that the system applies when there is more than one partner for a particular partner function. + * + * When you create a sales order for a particular customer, there may be more than one ship-to party defined. The different ship-to parties are numbered sequentially. + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Partner counter' + key PartnerCounter : String(3) not null; + /** The abbreviated form of the name that identifies the partner function. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Partner Function' + key PartnerFunction : String(2) not null; + @sap.display.format : 'UpperCase' + @sap.label : 'Customer' + @sap.quickinfo : 'Customer number of business partner' + BPCustomerNumber : String(10); + /** + * Sold-to party number sent in by the customer in delivery schedules. + * + * The system uses this number to automatically determine the ship-to party. + */ + @sap.label : 'Partner Description' + @sap.quickinfo : 'Cust.-Specif. Descr. of Business Partner (Plant, Stor. Loc.)' + CustomerPartnerDescription : String(30); + /** + * Specifies a partner as the default for a particular partner function. + * + * When you enter more than one partner for a particular partner function (for example, you define three different ship-to parties), you can select one partner as the default. During sales or purchasing processing, if you have defined multiple partners for a partner function, the system prompts you to choose just one partner. The system presents the default partner as the first choice in the pop-up window. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Default Partner' + DefaultPartner : Boolean; + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.creatable : 'false' +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Supplier' +entity API_BUSINESS_PARTNER.A_Supplier { + /** Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Supplier' + @sap.quickinfo : 'Account Number of Supplier' + key Supplier : String(10) not null; + /** + * The account number of the vendor with whom automatic payment transactions are carried out. + * + * The field is only needed if payments are not to be made directly to the vendor to whom the payable is owed. The same applies to bank collections of receivables.The specification in this field applies to all company codes. There is a further field in which every company code can enter an alternative payee separately. If both fields are filled, the company code specification has priority. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Alternative Payee' + @sap.quickinfo : 'Account Number of the Alternative Payee' + AlternativePayeeAccountNumber : String(10); + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); + /** Name with which the user who entered the master record was logged on in the R/3 System. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Created by' + @sap.quickinfo : 'Name of Person who Created the Object' + @sap.creatable : 'false' + @sap.updatable : 'false' + CreatedByUser : String(12); + /** Date on which the master record, or the part of the master record being viewed, was created. */ + @sap.display.format : 'Date' + @sap.label : 'Created on' + @sap.quickinfo : 'Date on which the Record Was Created' + @sap.creatable : 'false' + @sap.updatable : 'false' + CreationDate : Date; + /** Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer' + @sap.quickinfo : 'Customer Number' + Customer : String(10); + @sap.display.format : 'UpperCase' + @sap.label : 'Payment block' + @sap.quickinfo : 'Payment Block' + PaymentIsBlockedForSupplier : Boolean; + /** + * Indicates that the account is blocked for posting for all company codes. + * + * If you set this indicator, the system prevents users from posting items to this account and issues an error message to inform them that the account is blocked. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Posting Block' + @sap.quickinfo : 'Central Posting Block' + PostingIsBlocked : Boolean; + /** Indicates whether or not the supplier master record is blocked for all departments (that is, whether or not posting to this record is allowed at all). */ + @sap.display.format : 'UpperCase' + @sap.label : 'Purch. block' + @sap.quickinfo : 'Centrally imposed purchasing block' + PurchasingIsBlocked : Boolean; + /** + * The account group is a classifying feature within vendor master records. The account group determines: + * + * the number interval for the account number of the vendor,whether the number is assigned by the user or by the system,which specifications are necessary and/or possible in the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account Group' + @sap.quickinfo : 'Supplier Account Group' + SupplierAccountGroup : String(4); + @sap.display.format : 'UpperCase' + @sap.label : 'Supplier Name' + @sap.quickinfo : 'Supplier Full Name' + @sap.creatable : 'false' + @sap.updatable : 'false' + SupplierFullName : String(220); + @sap.label : 'Name of Supplier' + @sap.creatable : 'false' + @sap.updatable : 'false' + SupplierName : String(80); + /** + * VAT registration number (VAT reg.no.) of the customer, vendor or your company code. + * + * The VAT registration number is used within the EU for tax-exempt deliveries for the "EC sales list". The check rules are defined for each EU country and cannot be changed. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'VAT Registration No.' + @sap.quickinfo : 'VAT Registration Number' + VATRegistration : String(20); + @sap.display.format : 'Date' + @sap.label : 'Date of Birth' + @sap.quickinfo : 'Date of Birth of the Person Subject to Withholding Tax' + BirthDate : Date; + @sap.label : 'Int. Location No.' + @sap.quickinfo : 'Cocatenated International Location Number' + @sap.creatable : 'false' + @sap.updatable : 'false' + ConcatenatedInternationalLocNo : String(20); + /** + * Indicates that all data in this master record is to be deleted. + * + * To delete this data, you have to run the archiving program for Accounts Receivable or Payable. This program will archive all master records marked for deletion provided that there is no dependent data in them.Deletion flags can also be used in the program for deleting master data. You should, however, run this program only to delete test data prior to production startup. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Deletion flag' + @sap.quickinfo : 'Central Deletion Flag for Master Record' + DeletionIndicator : Boolean; + /** + * Specifies an additional master record in which the official address is stored. + * + * This address is used in Italy for business transactions with the tax office in Italy. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Fiscal address' + @sap.quickinfo : 'Account number of the master record with fiscal address' + FiscalAddress : String(10); + /** + * An industry is a distinct group of companies with the same basic business activity. The industry key is used in selecting data for evaluations (for example, a vendor master data list). You can specify industries such as trade, banking, service, manufacturing, health care, public service, media and so on. + * + * The industry field belongs to the general data area of customer and vendor master records. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Industry' + @sap.quickinfo : 'Industry key' + @sap.creatable : 'false' + @sap.updatable : 'false' + Industry : String(4); + /** + * Here you enter the first 7 digits of the international location number. + * + * The International Location Number (ILN) is assigned (in Germany by the Centrale for Coorganisation GmbH)) when a company is founded. It consists of 13 digits, the last digit being the check digit. There are two categories of location numbers:Participants who only need an ILN to cleary and unmistakably identify themselves for communication with the business partner are given a category 1 ILN. This cannot be used to identify articles by means of EAN.Participants who wish to assign the location numbers for their own enterprise areas are given a category 2 ILN. For a category 2 ILN, digits 1 to 7 are described as basis number. This is used as basis for the creation of article numbers (EAN). + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Int. location no. 1' + @sap.quickinfo : 'International location number (part 1)' + InternationalLocationNumber1 : String(7); + /** + * Here, you enter digits 8-12 of the 13-digit international location number. + * + * The international location number (ILN) is assigned when establishing a company (by the "Zentrale für Coorganisation GmbH" in Germany). It consists of 13 digits, the last of which is the check digit. There are two types of international location numbers:Subscribers who only need one ILN to identify themselves in communication with the business partner are given an ILN of type 1. These cannot be used for identifying articles by means of EAN.Subscribers who need to assign location numbers for their own company areas are given an ILN of type 2. Positions 1 through 7 of the ILN type 2 are known as the basis number. This basis number forms the basis for article numbers (EAN). + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Int. location no. 2' + @sap.quickinfo : 'International location number (Part 2)' + InternationalLocationNumber2 : String(5); + /** The check digit is derived from a special check digit procedure from digits of the previous international location numbers. In this way, you can check whether the ILN entered is actually valid. */ + @sap.display.format : 'NonNegative' + @sap.label : 'Check digit' + @sap.quickinfo : 'Check digit for the international location number' + InternationalLocationNumber3 : String(1); + /** + * Denotes a natural person. + * + * In the following countries, the system needs to know whether the taxpayer is a legal or natural person so that it can check the tax numbers correctly:BrazilBulgariaColombiaCroatiaGreeceItalyMexicoPeruSloveniaThailandUkraineThe flag is also used in conjunction with the Statement of Payments to Natural Persons report, as used in the Czech Republic and in Slovakia. This report only covers customers and vendors for whom you have set this indicator.In South Korea, it is used in conjunction with the Generic Withholding Tax Reporting program. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Natural Person' + IsNaturalPerson : String(1); + /** Classification of companies according to tax aspects. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax type' + ResponsibleType : String(2); + /** Date up to which the certification of the QM-system is valid. */ + @sap.display.format : 'Date' + @sap.label : 'QM System Valid To' + @sap.quickinfo : 'Validity date of certification' + SuplrQltyInProcmtCertfnValidTo : Date; + /** + * If a QM system is maintained by the supplier, you can store a description of the QM system here. + * + * If a material is activated for QM in procurement, the system initiates the following check whenever purchasing functions are carried out (for example, when a request for a quotation is made or if a purchase order is created):Whether the supplier's verified QM system, according to supplier master record or quality info-record (for a combination of supplier/material) meets the requirements for QM systems as specified in the material masterIn carrying out the check, the system relies on the defined assignments for target QM systems and actual QM systems in the Customizing application.If the check is unsuccessful, a warning message is issued when a request for quotation is initiated and an error message is issued for all other procurement activities. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Actual QM System' + @sap.quickinfo : 'Supplier''s QM system' + SuplrQualityManagementSystem : String(4); + /** + * If the customer or the vendor belongs to a group, you can enter a group key here. The group key is freely assignable. + * + * If you create a matchcode using this group key, group evaluations are possible. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Group Key' + SupplierCorporateGroup : String(10); + /** + * Key that determines which procurement functions (for example, request for quotation, purchase order, or goods receipt) should be blocked for quality reasons. + * + * You can enter a block key in the:Supplier master recordIn this case, the supplier block applies to all materials and plants.Quality info record for QM in procurementIn this case, the supplier block applies to a single material and plant.A block for quality reasons applies only to those materials for which QM in procurement is active. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Block Function' + @sap.quickinfo : 'Function That Will Be Blocked' + SupplierProcurementBlock : String(2); + /** + * Specifies the tax number. + * + * Enter the appropriate tax number:Country Tax NumberArgentina CUIT number or CUIL numberBelgium Enterprise numberBrazil CNPJ numberBulgaria Unified identification codeChile RUT numberChina VAT registration number (shui wu deng ji hao)Colombia NIT numberCroatia Legal persons: company identification numberNatural persons: JMBG numberCzech Republic DIC numberFrance SIRET numberGreece Personal IDHungary Tax numberItaly Fiscal codeKazakhstan RNN (obsolete)Mexico RFC numberNetherlands SI registration number (Aansluitnummer UWV) of chain- liability vendorNorway VAT numberPeru RUC numberPhilippines Taxpayer identification number (see below)Poland NIP numberPortugal NIF numberRomania Tax numberRussia INNSlovakia DIC numberSlovenia Tax numberSouth Korea Natural persons: Personal identification numberLegal persons: Corporation IDSpain NIF numberSwitzerland UID numberTaiwan - China GUI registration numberThailand Personal IDTurkey Name of business partner's tax officeUkraine Taxpayer identification numberUnited Kingdom Company registration numberUnited States Social security numberVenezuela RIF numberIn the Philippines, enter the taxpayer identification number with a V or N at the end, as follows:If the business partner is liable to VAT: 999-999-999-999VIf the business partner is not liable to VAT: 999-999-999-999N + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number 1' + @sap.creatable : 'false' + @sap.updatable : 'false' + TaxNumber1 : String(16); + /** + * Specifies the tax number. + * + * Enter the appropriate tax number:Country Tax NumberArgentina NIP number or CM numberBelgium VAT numberBrazil CPF numberBulgaria Legal persons: tax numberNatural persons: personal IDCroatia OIB number Czech Republic ICO numberFrance SIREN numberGreece AFM numberIndia TINItaly VAT numberKazakhstan BC (Beneficiary Code)Netherlands BSN numberRussia OKPO codeSlovakia ICO numberSouth Korea VAT registration numberSweden Organization registration numberSwitzerland VAT numberTaiwan - China Tax registration numberUkraine Legal persons: USREOU numberNatural persons: SRNP numberTurkey Tax numberUnited Kingdom NI numberUnited States Employer identification numberVenezuela NIT number + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number 2' + @sap.creatable : 'false' + @sap.updatable : 'false' + TaxNumber2 : String(11); + /** + * Specifies the tax number. + * + * Enter the tax number that applies:Country Tax numberArgentina Withholding agent numberBrazil State tax numberBulgaria Social security numberMexico CURP numberKazakhstan BINNetherlands Tax registration number (Loonbelastingnummer) of the chain-liability vendorRussia KPP numberThailand Tax ID Ukraine VAT registration number + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number 3' + @sap.creatable : 'false' + @sap.updatable : 'false' + TaxNumber3 : String(18); + /** + * Specifies the tax number. + * + * Enter the appropriate tax number:Country Tax NumberBrazil Municipal tax numberKazakhstan IINRussia OFK number (for public bodies only) + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number 4' + @sap.creatable : 'false' + @sap.updatable : 'false' + TaxNumber4 : String(18); + /** + * Kazakhstan + * + * Specifies the certificate of registration as VAT payer in the following format: XXXXXYYYYYYYZZZZZZZZ, where: XXXXX is the certificate serial number, YYYYYYY is the certificate number and ZZZZZZZZ is the date of certificate issue. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number 5' + @sap.creatable : 'false' + @sap.updatable : 'false' + TaxNumber5 : String(60); + /** The tax number of the vendor at the responsible tax authority. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number' + @sap.quickinfo : 'Tax Number at Responsible Tax Authority' + TaxNumberResponsible : String(18); + /** + * Taxes in Argentina: + * + * The format and the check of tax number 1 depend on the two-digit tax number type.The tax number type is an identification type for tax in Argentina (for example, 80 for CUIT) and is used for the DGI tax report. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number Type' + TaxNumberType : String(2); + /** + * This indicator controls the process of proof of delivery during the incoming goods process for inbound deliveries. Processing is activating by switching on this indicator in the supplier master and by switching on the corresponding indicator in the delivery item category. + * + * There are the following different characteristics:' ': not relevant for POD'A': generally relevant for POD'B': only relevant for POD if differences(Difference between notified quantity and actual quantity received) + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Relevant for POD' + @sap.quickinfo : 'Supplier indicator relevant for proof of delivery' + SuplrProofOfDelivRlvtCode : String(1); + /** + * Tax calculation for Brazil: + * + * The IPI tax value is split up for this vendor. 50% of the calculated IPI tax value is posted as deductible input tax, 50% is deducted from the inventory posting or posting to expense account. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax split' + @sap.quickinfo : 'Tax Split' + BR_TaxIsSplit : Boolean; + @cds.ambiguous : 'missing on condition?' + to_SupplierCompany : Association to many API_BUSINESS_PARTNER.A_SupplierCompany { }; + @cds.ambiguous : 'missing on condition?' + to_SupplierPurchasingOrg : Association to many API_BUSINESS_PARTNER.A_SupplierPurchasingOrg { }; +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Supplier Company' +entity API_BUSINESS_PARTNER.A_SupplierCompany { + /** Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Supplier' + @sap.quickinfo : 'Account Number of Supplier' + key Supplier : String(10) not null; + /** The company code is an organizational unit within financial accounting. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Company Code' + key CompanyCode : String(4) not null; + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); + @sap.label : 'Company Name' + @sap.quickinfo : 'Name of Company Code or Company' + @sap.creatable : 'false' + @sap.updatable : 'false' + CompanyCodeName : String(25); + /** + * Block key (enqueue key) that is used to block an open item or an account to payment transactions. + * + * You can use the block key as described below.Automatic Payment TransactionsIn automatic payment transactions, the block takes effect when it is entered in the system as follows:In the master recordIn the documentIf you enter the block in the master record then all open items for this account are contained in the exception list.The following block keys have a special meaning in the master record:The block key * has the effect that all items of the account are skipped in automatic payment transactions.The block key + has the effect that all items are skipped in which a payment method was not entered explicitly.The block key A is always set automatically when a down payment is entered. Therefore, you must not delete the block key A or use it for other purposes.Whether a block key can be set or removed in payment proposal processing depends on the attribute Changeable in payment proposal of the block key.Manual PaymentsManual payments are only affected by a block key in the document if you set the attribute Blocked for manual payments in the block key.A block key that was set in the master record does not have any effect on manual payments. You can have the system issue a warning message in that case. To do so, you have to make system settings. Set up message 671 of work area F5 in message control accordingly. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Payment Block' + @sap.quickinfo : 'Block Key for Payment' + PaymentBlockingReason : String(1); + /** + * Indicates that the account is blocked for posting in the specified company code. + * + * If you set this indicator, the system prevents users from posting items to this account and issues an error message to inform them that the account is blocked. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Co.code post.block' + @sap.quickinfo : 'Posting block for company code' + SupplierIsBlockedForPosting : Boolean; + /** + * Identification code for the accounting clerk. + * + * The name of the accounting clerk defined by this identification code can be used in the payment program for correspondence and reporting (for example, open item lists). + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Clerk Abbrev.' + @sap.quickinfo : 'Accounting Clerk Abbreviation' + AccountingClerk : String(2); + @sap.label : 'Acctg clerk''s fax' + @sap.quickinfo : 'Accounting clerk''s fax number at the customer/vendor' + AccountingClerkFaxNumber : String(31); + @sap.display.format : 'UpperCase' + @sap.label : 'Acct.clerks tel.no.' + @sap.quickinfo : 'Accounting clerk''s telephone number at business partner' + AccountingClerkPhoneNumber : String(30); + /** Name or identification code of the accounting clerk at the vendor. */ + @sap.label : 'Clerk at vendor' + SupplierClerk : String(15); + @sap.label : 'Clrk''s internet add.' + @sap.quickinfo : 'Internet address of partner company clerk' + SupplierClerkURL : String(130); + /** + * List of payment methods which may be used in automatic payment transactions with this customer/vendor if you do not specify a payment method in the item to be paid. + * + * If you do specify a particular payment method in the item to be paid, this specification has priority over the specifications in the master record. You may also specify payment methods in the item which are not listed in the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Payment Methods' + @sap.quickinfo : 'List of Respected Payment Methods' + PaymentMethodsList : String(10); + /** + * Key for defining payment terms composed of cash discount percentages and payment periods. + * + * It is used in sales orders, purchase orders, and invoices. Terms of payment provide information for:Cash managementDunning proceduresPayment transactionsData can be entered in the field for the terms of payment key in various ways as you enter a business transaction:In most business transactions, the system defaults the key specified in the master record of the customer/vendor in question.In some transactions (for example, credit memos), however, the system does not default the key from the master record. Despite this, you can use the key from the customer/vendor master record by entering "*" in the field.Regardless of whether or not a key is defaulted from the master record, you can manually enter a key during document entry at:item level in sales ordersheader level in purchase orders and invoicesMaster records have separate areas for Financial Accounting, Sales, and Purchasing. You can specify different terms of payment keys in each of these areas. When you then enter a business transaction, the application in question will use the key specified in its area of the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Terms of Payment' + @sap.quickinfo : 'Terms of Payment Key' + PaymentTerms : String(4); + /** + * Indicates that during automatic payment transactions, clearing is made with the corresponding customer account, and that during manual clearing procedures, the items of that customer account are also selected. + * + * To use this function in automatic payment transactions, you have toenter the customer account number in the vendor master record,enter the vendor account number in the customer master record, andselect the "Clearing with vendor" indicator in the customer master record.If this indicator is set, items belonging to the customer account will be included in any dunning run. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Clearing with cust.' + @sap.quickinfo : 'Indicator: Clearing between customer and vendor?' + ClearCustomerSupplier : Boolean; + /** + * Indicates that payment transactions and dunning notices are created for the branch. + * + * Normally automatic payment transactions and dunning notices are created for the head office.NoteSelect this indicator only if this account is a head office account. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Local Processing' + @sap.quickinfo : 'Indicator: Local Processing?' + IsToBeLocallyProcessed : Boolean; + /** If this indicator is set, every customer/vendor open item is paid separately during automatic payment transactions. This means that open items are not grouped together for payment. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Individual Payment' + @sap.quickinfo : 'Indicator: Pay All Items Separately?' + ItemIsToBePaidSeparately : Boolean; + /** This indicator specifies that the customer/vendor should be sent all payment advice information by EDI. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Pmnt advice by EDI' + @sap.quickinfo : 'Indicator: Send Payment Advices by EDI' + PaymentIsToBeSentByEDI : Boolean; + /** All bank data is determined using this key. */ + @sap.display.format : 'UpperCase' + @sap.label : 'House Bank' + @sap.quickinfo : 'Short Key for a House Bank' + HouseBank : String(5); + /** + * Number of days which usually pass until the vendor has cashed your check. + * + * During automatic payment transactions, the system calculates the value date for check payments using this information and stores the date in the line item. The date is calculated as follows:Value date = posting date + check cashing timeIn Cash Management, the value date is used as information about the expected cash outflow. + */ + @sap.label : 'Check Cashing Time' + @sap.quickinfo : 'Probable Time Until Check Is Paid' + CheckPaidDurationInDays : Decimal(3, 0); + /** Currency key for amounts in the system. */ + @sap.label : 'Currency' + @sap.quickinfo : 'Currency Key' + @sap.semantics : 'currency-code' + Currency : String(5); + /** + * Maximum amount which may be issued on a bill of exchange if it is to be used in payment transactions with the business partner. + * + * The amount limit is taken into consideration in automatic payment transactions for payments by bill of exchange and bill of exchange payment requests. Several bill of exchange forms are created if the amount to be settled is higher than the maximum amount given here. Each of these bills of exchange is issued for the maximum amount or for a smaller amount.Amount limits for bills of exchange are used in Spain, for example. + */ + @sap.unit : 'Currency' + @sap.label : 'Bill/Ex. Limit' + @sap.quickinfo : 'Bill of Exchange Limit (in Local Currency)' + BillOfExchLmtAmtInCoCodeCrcy : Decimal(14, 3); + /** This field contains the account number the company is listed under at the vendor. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account with vendor' + @sap.quickinfo : 'Our account number with the vendor' + SupplierClerkIDBySupplier : String(12); + /** + * The reconciliation account in G/L accounting is the account which is updated parallel to the subledger account for normal postings (for example, invoice or payment). + * + * For special postings (for example, down payment or bill of exchange), this account is replaced by another account (for example, 'down payments received' instead of 'receivables').The replacement takes place due to the special G/L indicator which you must specify for these types of postings. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Reconciliation Acct' + @sap.quickinfo : 'Reconciliation Account in General Ledger' + ReconciliationAccount : String(10); + /** Enter an interest calculation indicator here if the account is to be included in automatic interest calculation. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Interest indicator' + @sap.quickinfo : 'Interest calculation indicator' + InterestCalculationCode : String(2); + /** + * The date in this field displays the last time the interest calculation program processed this account. This is generally the upper limit of the last interest run. + * + * Generally, this date is automatically maintained by the program (batch input). A manual entry in this field should only be made if an error has occurred or when implementing the interest calculation. + */ + @sap.display.format : 'Date' + @sap.label : 'Last Key Date' + @sap.quickinfo : 'Key Date of Last Interest Calculation' + InterestCalculationDate : Date; + /** + * This field contains the account number of the master record for the head office account. + * + * You specify this account number only for branch accounts. Items that you post using the branch account number are automatically posted to the head office account. The system records the branch account number in the line items.Neither transactions nor balances are kept in the branch account. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Head office' + @sap.quickinfo : 'Head office account number' + SupplierHeadOffice : String(10); + /** + * The account number of the vendor with whom automatic payment transactions are to be carried out. + * + * The field is only needed if payments are not to be made directly to the vendor to whom the payable is owed. The same applies to bank collections of receivables.The specification in this field applies only to the company code. There is a further field in which you can enter an alternative payee for each company code. If both fields are filled, the company code specified has priority. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Alternative payee' + @sap.quickinfo : 'Account number of the alternative payee' + AlternativePayee : String(10); + /** + * Indicates the layout rule for the Allocation field in the document line item. + * + * The system uses a standard sort sequence for displaying line items. Among other things, it sorts the items according to the content of the Allocation field. This field can be filled either manually or automatically (by the system) when a document line item is entered.For this purpose, the system requires rules that determine which information is to be taken from the document header or from the document line item and placed in the field. The rules can be stored in the master record of an account which enables you to determine the standard sort sequence on an account-specific basis.NoteField information from another document line item cannot be adopted into the field of a particular item. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Sort Key' + @sap.quickinfo : 'Key for Sorting According to Assignment Numbers' + LayoutSortingRule : String(3); + /** Contains settings that control how the system handles differences between the invoice amount and the amount received from a customer or the amount paid to a supplier. A tolerance group is unique within a company code. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tolerance Group' + @sap.quickinfo : 'Tolerance Group for Business Partner/G/L Account' + APARToleranceGroup : String(4); + /** + * US government requirement. + * + * Date field in which to enter certification date for small companies run by women or minorities. This certificate must be renewed every two years. + */ + @sap.display.format : 'Date' + @sap.label : 'Certification Date' + SupplierCertificationDate : Date; + /** + * Internal memo of the accounting department. + * + * The memo serves only as information on special features of the customer/vendor. + */ + @sap.label : 'Account Memo' + @sap.quickinfo : 'Memo' + SupplierAccountNote : String(30); + /** + * In some countries, an additional country is needed for calculating or reporting withholding tax. + * + * The calculation can depend on the payee's country.A particular country key can be required by law for reporting which may possibly be different to the key used in the address.Examples: Japan, USA (1042), Argentina + */ + @sap.display.format : 'UpperCase' + @sap.label : 'WTax Country' + @sap.quickinfo : 'Withholding Tax Country Key' + WithholdingTaxCountry : String(3); + /** + * Indicates that the company code data in this master record is to be deleted. + * + * To delete this data, you have to run the archiving program for Accounts Receivable or Payable. This program will archive all master records marked for deletion provided that there is no dependent data in them.This deletion flag cannot be used in the program that deletes master data. You should, however, run this program only to delete test data prior to production startup. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Co.cde deletion flag' + @sap.quickinfo : 'Deletion Flag for Master Record (Company Code Level)' + DeletionIndicator : Boolean; + /** + * In cash management, customers and vendors are allocated to planning groups by means of an entry made in the master record. + * + * You can define these planning groups in Customizing or the Implementation Guide (you will need to ensure that they are all the same length). In order to improve the liquidity forecast display for major customers and vendors, it can be advisable to enter their account number as the planning group.For the planning groups themselves a naming convention should be set up to improve liquidity forecasting. In the following examples, the customer planning groups begin with an "R" for receipts, and the vendor planning groups begin with an "E" for expenses.R1 Customers paying by bank collectionR2 Other domestic customersR3 Customers abroadR4 Affiliated company customersR5 High risk customersR6 Major customersR7 Rental incomeR8 Repayment of loans...E1 Domestic vendorsE2 Vendors abroadE3 Affiliated company vendorsE4 Major vendorsE5 Personnel costsE6 TaxesE7 Investments... + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Planning Group' + CashPlanningGroup : String(10); + /** + * When incoming invoices are entered or when memos are entered in Financial Accounting (FI), the system checks whether an invoice or credit memo has already been entered for the same date. + * + * Checking Logistics DocumentsThe system checks whether the invoice documents have already been entered in the Logistics invoice verification. For this, the system checks invoices that have been held or parked or that contain errors, or invoices that were entered for invoice verification in the background. The check is performed only if you specify the reference document number when you enter the invoices.When checking for duplicate invoices, the system compares the following specified characteristics:VendorCurrencyCompany CodeGross Invoice AmountReference Document NumberInvoice Document DateIf all of these characteristics are the same, the system issues a message for which you can change the message type in Customizing.When you enter credit memos or subsequent adjustments, the system does not check for duplicate invoices.Exception: The exception is the Argentina country version, where the system checks for duplicate invoices and credit memos.No message is issued if you enter a document that has previously been reversed.In Customizing for Logistics Invoice Verification under Incoming Invoice -> Set Check for Duplicate Invoices, you can specify that the following characteristics are not checked:Reference Document NumberInvoice Document DateCompany CodeHaving fewer attributes to check increases the likelihood that the system will find a duplicate invoice.Example:The following document has already been entered and posted:Reference Document Number 333Invoice Date: 4/28/2000Gross Invoice Amount 100.00Currency: EURVendor: SpencerCompany Code: ChicagoYou have set up the check for duplicate invoices as follows in Customizing:The characteristics Reference Document Number and Company Code are not activated. Consequently, these characteristics are not checked.Now you enter the following invoice:Reference Document Number 334Invoice Date: 4/28/2000Gross Invoice Amount 100.00Currency: EURVendor: SpencerCompany Code: FlagstaffResultBecause you entered a reference document when you entered the invoice, the system checks for duplicate invoices. Compared against the invoice entered earlier, the invoice just entered has different values in the characteristics Reference and Company Code. However, these characteristics are not checked due to the settings that you have made in Customizing. All other characteristics are the same. The system issues a message telling you that an invoice has been entered twice.If the characteristic "Reference Document Number" had been selected in Customizing, the system would have checked the reference document number and established that it was different from the invoice entered earlier, and it consequently would not have issued a message.Checking FI DocumentsThe system checks whether there are FI documents that were posted or parked with the Logistics invoice verification or with an FI invoice transaction. Depending on the entry in the Reference field, one of the following checks is performed:If a reference number was specified in the sequential invoice/credit memo, the system checks whether an invoice/credit memo has already been posted for which all the following attributes agree:Company CodeVendorCurrencyDocument DateReference NumberIf no reference number was specified in the sequential invoice/credit memo, the system checks whether an invoice/credit memo has already been posted for which all the following attributes agree:Company CodeVendorCurrencyDocument DateAmount in Document CurrencyIn Materials Management, the system applies the check for duplicate invoices for invoices only, not for credit memos. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Check Double Invoice' + @sap.quickinfo : 'Check Flag for Double Invoices or Credit Memos' + IsToBeCheckedForDuplicates : Boolean; + @sap.display.format : 'UpperCase' + @sap.label : 'Minority Indicator' + MinorityGroup : String(3); + /** + * The account group is a classifying feature within vendor master records. The account group determines: + * + * the number interval for the account number of the vendor,whether the number is assigned by the user or by the system,which specifications are necessary and/or possible in the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account Group' + @sap.quickinfo : 'Supplier Account Group' + SupplierAccountGroup : String(4); + @cds.ambiguous : 'missing on condition?' + to_SupplierDunning : Association to many API_BUSINESS_PARTNER.A_SupplierDunning { }; + @cds.ambiguous : 'missing on condition?' + to_SupplierWithHoldingTax : Association to many API_BUSINESS_PARTNER.A_SupplierWithHoldingTax { }; +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Supplier Dunning' +entity API_BUSINESS_PARTNER.A_SupplierDunning { + /** Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Supplier' + @sap.quickinfo : 'Account Number of Supplier' + key Supplier : String(10) not null; + /** The company code is an organizational unit within financial accounting. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Company Code' + key CompanyCode : String(4) not null; + /** + * The dunning area represents an organizational entity that is responsible for dunning. The dunning areas represent a sub-structure of the company codes. + * + * If different responsibilities or different dunning procedures exist within a company code, you can set up corresponding dunning areas.All dunning notices are made separately according to dunning areas, and if necessary with different dunning procedures.The dunning area must be noted in the line items. As long as documents are copied from preliminary work areas (billing documents), the dunning area can be derived from details such as division or sales area, if necessary. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Dunning Area' + key DunningArea : String(2) not null; + /** Key which reflects the reason for a dunning block indicator. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Dunning Block' + DunningBlock : String(1); + /** + * Number that specifies how often an item or account has been dunned. + * + * The business partner has received the dunning level from the last dunning run.If you use dunning areas, it is the dunning level that the business partner received from the last dunning run in the dunning area assigned.The dunning program sets the dunning level automatically when the customer or vendor receives a dunning notice. + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Dunning Level' + DunningLevel : String(1); + /** This field contains the key for the dunning procedure to be used. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Dunning Procedure' + DunningProcedure : String(4); + /** + * Account number of the vendor who is to receive the dunning notice. + * + * Note:If an entry is not made in this field, the dunning notice is sent to the address of the vendor to be processed. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Dunn.recipient' + @sap.quickinfo : 'Account number of the dunning recipient' + DunningRecipient : String(10); + /** Date on which the last dunning notice was made. */ + @sap.display.format : 'Date' + @sap.label : 'Last Dunned' + @sap.quickinfo : 'Date of Last Dunning Notice' + LastDunnedOn : Date; + /** + * Date on which a legal dunning procedure was initiated. + * + * The printing of dunning notices in the legal dunning procedure generates an internal notice about any further account movements. A dunning notice is not created for the customer.If the Legal dunning procedure field in the master record contains a date, this means that the account is involved in a legal dunning procedure. The relationship between this date and the dunning date does not affect how the account is processed.The printing of account movements in the legal dunning procedure differs from the normal printing of dunning notices as follows:You must specify a separate form for your dunning procedure in Customizing. For more information, see Customizing (IMG) under Dunning Forms.The dunning program also displays text element 520 "Legal dunning procedure". This makes it possible to display the date of the legal dunning procedure from the master record.The program also displays the documents blocked for dunning and those with a payment method (automatic debit, bank direct debit).Although dunning notices are printed, the dunning level does not change in the master record or in the items. New dunning level = old dunning level.The program only updates the date of the last dunning run.Enter the date manually. + */ + @sap.display.format : 'Date' + @sap.label : 'Legal Dunn.Proc.From' + @sap.quickinfo : 'Date of the Legal Dunning Proceedings' + LegDunningProcedureOn : Date; + /** + * Identification code for the accounting clerk dealing with dunning letters. + * + * Using this identification code, the accounting clerk whose name is printed on the dunning letters is determined.If this field is not filled, then the entry from the Accounting clerk field is used. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Dunning Clerk' + DunningClerk : String(2); + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); + /** + * The account group is a classifying feature within vendor master records. The account group determines: + * + * the number interval for the account number of the vendor,whether the number is assigned by the user or by the system,which specifications are necessary and/or possible in the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account Group' + @sap.quickinfo : 'Supplier Account Group' + SupplierAccountGroup : String(4); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Purchasing Partner Functions' +entity API_BUSINESS_PARTNER.A_SupplierPartnerFunc { + /** Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Supplier' + @sap.quickinfo : 'Account Number of Supplier' + key Supplier : String(10) not null; + /** Denotes the purchasing organization. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Purch. Organization' + @sap.quickinfo : 'Purchasing Organization' + key PurchasingOrganization : String(4) not null; + /** + * Subdivision of a supplier's overall product range according to various criteria. + * + * For each supplier sub-range:The master data is kept on a common basisCertain conditions applyIn the supplier master, you can create different purchasing data and different partner functions for each supplier sub-range.You can also maintain and change the conditions for each supplier sub-range. You assign a material to a supplier sub-range in the info record.In the supplier master, you can maintain different data for particular supplier sub-ranges, such as ordering addresses or terms of payment, for example.When creating a purchase order with a known supplier, different data is only determined if the supplier sub-range is entered in the initial screen.Your supplier Smith in Houston has two sub-ranges: paint and glue.All materials from the "paint" sub-range are ordered in Houston.You have maintained an alternative ordering address in Detroit for the "glue" sub-range.If you order materials from the "glue" sub-range, the supplier sub-range finds the Detroit ordering address. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Supplier Subrange' + key SupplierSubrange : String(6) not null; + /** Key uniquely identifying a plant. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Plant' + key Plant : String(4) not null; + /** The abbreviated form of the name that identifies the partner function. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Partner Function' + key PartnerFunction : String(2) not null; + /** + * The sequential number that the system applies when there is more than one partner for a particular partner function. + * + * When you create a sales order for a particular customer, there may be more than one ship-to party defined. The different ship-to parties are numbered sequentially. + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Partner counter' + key PartnerCounter : String(3) not null; + /** + * Specifies a partner as the default for a particular partner function. + * + * When you enter more than one partner for a particular partner function (for example, you define three different ship-to parties), you can select one partner as the default. During sales or purchasing processing, if you have defined multiple partners for a partner function, the system prompts you to choose just one partner. The system presents the default partner as the first choice in the pop-up window. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Default Partner' + DefaultPartner : Boolean; + @sap.display.format : 'Date' + @sap.label : 'Created On' + @sap.quickinfo : 'Date on Which Record Was Created' + @sap.creatable : 'false' + @sap.updatable : 'false' + CreationDate : Date; + @sap.display.format : 'UpperCase' + @sap.label : 'Created By' + @sap.quickinfo : 'Name of Person Who Created Object' + @sap.creatable : 'false' + @sap.updatable : 'false' + CreatedByUser : String(12); + @sap.display.format : 'UpperCase' + @sap.label : 'Ref. to vendor' + @sap.quickinfo : 'Reference to other vendor' + ReferenceSupplier : String(10); + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Purchasing Organization' +entity API_BUSINESS_PARTNER.A_SupplierPurchasingOrg { + /** + * Alphanumeric key uniquely identifying the document. + * + * With the supplier number, information from the supplier master record (such as the supplier's address and bank details) is copied into a purchasing document (such as a request for quotation or a purchase order).You can use the supplier number to keep track of requests for quotation, purchase orders and outline agreements. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Supplier' + @sap.quickinfo : 'Supplier''s Account Number' + key Supplier : String(10) not null; + /** Denotes the purchasing organization. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Purch. Organization' + @sap.quickinfo : 'Purchasing Organization' + key PurchasingOrganization : String(4) not null; + /** + * Determines which calculation schema (pricing procedure) is to be used in purchasing documents containing this supplier number. + * + * You can use the schema group to specify the calculation schema per purchasing organization or supplier. The relevant calculation schema is determined by reference to the schema group.The effect of this is that the conditions to be maintained in a purchasing document can differ depending on the relevant purchasing organization or supplier.If a calculation schema is only to be valid for certain purchasing organizations or suppliers, proceed as follows:Define the schema group for the purchasing organization or the supplier using the relevant function in the menu "Calculation schema -> Schema groups".Assign the schema group to the calculation schema via "Calculation schema -> Determine schema".Enter the schema group for the supplier in the supplier master records to which the calculation schema is to be assigned. Assign the schema group of the purchasing organization to the relevant purchasing organization using "Calculation schema -> Schema group -> Assign to purch. org.". + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Schema Grp, Supplier' + @sap.quickinfo : 'Group for Calculation Schema (Supplier)' + CalculationSchemaGroupCode : String(2); + /** Indicates whether or not the supplier master record is earmarked for deletion. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Del. flag POrg.' + @sap.quickinfo : 'Deletion Indicator for Supplier at Purchasing Level' + DeletionIndicator : Boolean; + /** + * Commonly used trading terms that comply with the standards established by the International Chamber of Commerce (ICC). + * + * Incoterms specify internationally recognized procedures that the shipper and the receiving party must follow for the shipping transaction to be completed successfully.If goods are shipped through a port of departure, the appropriate Incoterm might be: FOB ("Free On Board"). You can provide further details (for example, the name of the port) in the secondary Incoterm field: FOB Boston, for example. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Incoterms' + @sap.quickinfo : 'Incoterms (Part 1)' + IncotermsClassification : String(3); + /** + * Additional information for the primary Incoterm. + * + * If the primary Incoterm is, for example, FOB ("Free on Board"), then the second field provides details of the port from which the delivery leaves (for example, "FOB Boston"). + */ + @sap.label : 'Incoterms (Part 2)' + IncotermsTransferLocation : String(28); + /** An incoterms version is an edition containing a list of international terms for transportation that is defined by the International Chamber of Commerce (ICC). */ + @sap.display.format : 'UpperCase' + @sap.label : 'Incoterms Version' + IncotermsVersion : String(4); + /** + * Provides additional information for the primary Incoterm. For Incoterms 2010, this field represents: + * + * 1. For sea and inland waterway transport - Port of Shipment2. For any mode of transport - Place of Delivery 2010Incoterms are divided as follows:Group 1: Rules for any mode or modes of transport (including by vessel)Incoterms Incoterms Description Location 1 EXW Ex Works Place of DeliveryFCA Free Carrier Place of DeliveryCPT Carriage Paid To Place of DestinationCIP Carriage & Insurance Paid To Place of DestinationDAF Delivered at Frontier Place of DeliveryDDP Delivered Duty Paid Place of DestinationDDU Delivered Duty Unpaid Place of DestinationGroup 2: Rules for sea and inland waterwaysIncoterms Incoterms Description Location 1 FAS Free Alongside Ship Port of ShipmentFOB Free On Board Port of ShipmentCFR Cost & Freight Port of DestinationCIF Cost Insurance & Freight Port of DestinationDEQ Delivered Eq Quay (Duty Paid) Port of DestinationDES Delivered Ex Ship Port of DestinationIf the primary incoterm is specified as FOB “Free on Board”, the second field provides details of the port from which the delivery leaves, such as FOB Boston. + */ + @sap.label : 'Incoterms Location 1' + IncotermsLocation1 : String(70); + /** + * Provides additional information for the Incoterms. This field is only available for C-Clauses (if customized appropriately). Note the following for the incoterms versions below: + * + * No Version:This field is disabledIncoterm Version 2000This field is disabled as part of standard delivery unless a customer decides to enable it by the way of Customizing for Sales and Distribution under Master Data -> Business Partners -> Customers -> Billing Document -> Incoterms -> Map Incoterms to Versions.Incoterm Version 2010For this version, the field represents:Sea and inland waterway transport - Port of DestinationAny mode of transport - Place of Destination2010 Incoterms are divided as follows:Group 1: Rules for any mode or modes of transport (including by vessel)Incoterms Incoterms Description Location 2CPT Carriage Paid To Place of DestinationCIP Carriage & Insurance Paid To Place of DestinationGroup 2: Rules for sea and inland waterwaysIncoterms Incoterms Description Location 2CFR Cost & Freight Port of DestinationCIF Cost Insurance & Freight Port of Destination + */ + @sap.label : 'Incoterms Location 2' + IncotermsLocation2 : String(70); + /** Indicator specifying that provision has been made for goods-receipt-based invoice verification for a purchase order item or invoice item. */ + @sap.display.format : 'UpperCase' + @sap.label : 'GR-Based Inv. Verif.' + @sap.quickinfo : 'Indicator: GR-Based Invoice Verification' + InvoiceIsGoodsReceiptBased : Boolean; + /** + * Number of calendar days needed to obtain the material or service if it is procured externally. + * + * If you have different vendors for a material, you must specify an average value. The same applies if you order the material from a fixed vendor that has varying delivery times.If you use the SAP Retail System, the planned delivery time can be suggested from the vendor sub-range in the vendor master record. + */ + @sap.label : 'Planned Deliv. Time' + @sap.quickinfo : 'Planned Delivery Time in Days' + MaterialPlannedDeliveryDurn : Decimal(3, 0); + /** Minimum value specified for purchase orders issued to the relevant supplier. */ + @sap.unit : 'PurchaseOrderCurrency' + @sap.label : 'Minimum order value' + MinimumOrderAmount : Decimal(14, 3); + /** + * Key for defining payment terms composed of cash discount percentages and payment periods. + * + * It is used in sales orders, purchase orders, and invoices. Terms of payment provide information for:Cash managementDunning proceduresPayment transactionsData can be entered in the field for the terms of payment key in various ways as you enter a business transaction:In most business transactions, the system defaults the key specified in the master record of the customer/vendor in question.In some transactions (for example, credit memos), however, the system does not default the key from the master record. Despite this, you can use the key from the customer/vendor master record by entering "*" in the field.Regardless of whether or not a key is defaulted from the master record, you can manually enter a key during document entry at:item level in sales ordersheader level in purchase orders and invoicesMaster records have separate areas for Financial Accounting, Sales, and Purchasing. You can specify different terms of payment keys in each of these areas. When you then enter a business transaction, the application in question will use the key specified in its area of the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Terms of Payment' + @sap.quickinfo : 'Terms of Payment Key' + PaymentTerms : String(4); + /** + * Determines which date is to be used for price determination (pricing) purposes. + * + * Enter the key for the desired date.If you choose the date of goods receipt, for example, a new price will be determined upon the arrival of the goods, causing the item to be revaluated at this time.NoteIf you have chosen the delivery date as the date for price determination and an item contains several delivery dates (i.e. has a delivery schedule), the first delivery date (the delivery date specified in the first schedule line) is taken. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Pricing Date Control' + @sap.quickinfo : 'Price Determination (Pricing) Date Control' + PricingDateControl : String(1); + /** + * Allows you to automatically generate purchase orders from purchase requisitions if the requisition has been assigned to a supplier (source of supply). + * + * If you want to use automatic conversion, note the following additional conditions:In the case of purchase requisitions for materials, you should also select the indicator Autom.purch.ord. in the Purchasing view in the material master record.In the case of purchase requisitions for services, you should also select the indicator Automatic creation of POs for service PReqs in Customizing for Services by choosing:IMG -> MM -> External Services Management -> Source Determination and Default Values- for Client or- for Purchasing Organization + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Automatic PO' + @sap.quickinfo : 'Automatic Generation of Purchase Order Allowed' + PurOrdAutoGenerationIsAllowed : Boolean; + /** Key for the currency on which an order placed with a supplier is based. */ + @sap.label : 'Order currency' + @sap.quickinfo : 'Purchase order currency' + @sap.semantics : 'currency-code' + PurchaseOrderCurrency : String(5); + /** + * Key for a buyer or a group of buyers, who is/are responsible for certain purchasing activities. + * + * Internally, the purchasing group is responsible for the procurement of a material or a class of materials.Externally, it is the medium through which contacts with the vendor are maintained. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Purchasing Group' + PurchasingGroup : String(3); + /** Indicates whether or not the supplier master record is blocked for the purchasing organization for posting purposes. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Pur. block POrg' + @sap.quickinfo : 'Purchasing block at purchasing organization level' + PurchasingIsBlockedForSupplier : Boolean; + /** + * General shipping strategy for the delivery of goods from the vendor to the customer. + * + * You can define shipping conditions in your system which correspond to the requirements of your company. You can specify a shipping condition in the customer master and in the vendor master.Shipping point determination (outbound delivery):The loading group, the plant and the shipping condition determine the shipping point that will be proposed by the system.Route determination (outbound delivery):Apart from the country and the geographical region of the shipping point, the ship-to party and the transportation group, the shipping condition determines the route that the system proposes in the order for the delivery of the goods. In the delivery, the route proposal also takes the weight group into account.A particular customer always requires immediate delivery. You enter the appropriate shipping condition into the customer master record. This means that when you process orders for this customer, the system automatically proposes the express mail room as a shipping point and the quickest way to the airport as a route.If a shipping condition has been assigned to a sales document type in Customizing, this condition will be proposed by the system in the corresponding sales document. If there is no assignment, the system copies the relevant data from the corresponding customer master record of the sold-to party. You cannot change this value during delivery processing. The shipping condition will not be copied from the delivery into the shipment. The shipping condition is one of several criteria for selecting deliveries when you create a shipment. You can enter a shipping condition manually in the shipment where it only serves as a characteristic for grouping shipments. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Shipping Conditions' + ShippingCondition : String(2); + /** + * Means of classifying suppliers according to their significance to your company. + * + * The indicator serves to assign the supplier to one of the categories A, B or C, in accordance with ABC analysis.'A' category suppliers, for instance, are those accounting for the greatest share of the company's total annual spend (in value terms). + */ + @sap.display.format : 'UpperCase' + @sap.label : 'ABC indicator' + SupplierABCClassificationCode : String(1); + /** This telephone number is maintained in the supplier master record and adopted in the purchasing document. */ + @sap.label : 'Telephone' + @sap.quickinfo : 'Supplier''s Telephone Number' + SupplierPhoneNumber : String(16); + @sap.label : 'Salesperson' + @sap.quickinfo : 'Responsible Salesperson at Supplier''s Office' + SupplierRespSalesPersonName : String(30); + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); + /** + * The account group is a classifying feature within vendor master records. The account group determines: + * + * the number interval for the account number of the vendor,whether the number is assigned by the user or by the system,which specifications are necessary and/or possible in the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account Group' + @sap.quickinfo : 'Supplier Account Group' + SupplierAccountGroup : String(4); + @cds.ambiguous : 'missing on condition?' + to_PartnerFunction : Association to many API_BUSINESS_PARTNER.A_SupplierPartnerFunc { }; +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Company Withholding Tax' +entity API_BUSINESS_PARTNER.A_SupplierWithHoldingTax { + /** Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Supplier' + @sap.quickinfo : 'Account Number of Supplier' + key Supplier : String(10) not null; + /** The company code is an organizational unit within financial accounting. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Company Code' + key CompanyCode : String(4) not null; + /** + * This indicator is used to classify the different types of withholding tax. + * + * Withholding tax types classify particular features of a withholding tax including:The time at which the withholding tax is postedThe basis on which the base amount is calculatedThe basis for accumulation (if applicable)Withholding tax types are to be distinguished from withholding tax codes, to which are allocated the withholding tax percentage rate example.Whether a withholding tax can be defined as an existing type by means of a new code, or if a new type needs to be defined will depend on the type of transaction (see below).Note that a business transaction can only be assigned one withholding tax code per withholding tax type. If the business transaction is subject to several withholding taxes simultaneously, these must be represented by different types.This is the case in Argentina for example, where up to four kinds of withholding tax per business transaction are possible. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Withholding Tax Type' + @sap.quickinfo : 'Indicator for Withholding Tax Type' + key WithholdingTaxType : String(2) not null; + /** Date from which withholding tax exemption applies. */ + @sap.display.format : 'Date' + @sap.label : 'Exemption Start Date' + @sap.quickinfo : 'Date on Which Exemption Begins' + ExemptionDateBegin : Date; + /** Date on which withholding tax exemption expires. */ + @sap.display.format : 'Date' + @sap.label : 'Exemption End Date' + @sap.quickinfo : 'Date on Which Exemption Ends' + ExemptionDateEnd : Date; + /** + * Indicator used to classify different types of exemption from liability to a particular withholding tax. + * + * These indicators can be defined per withholding tax type in the vendor master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Exemption Reason' + @sap.quickinfo : 'Reason for Exemption' + ExemptionReason : String(2); + @sap.display.format : 'UpperCase' + @sap.label : 'Subject to W/Tx' + @sap.quickinfo : 'Indicator: Subject to Withholding Tax?' + IsWithholdingTaxSubject : Boolean; + /** + * The type of recipient can be defined in the vendor master record. + * + * It is used to group vendors together according to particular characteristics such as occupations that may be subject to the same withholding tax type, but which are required to pay different percentage rates (as defined by the withholding tax code).Application in ThailandThis corresponds to the official Thai form number (Phaw.Ngor.Daw) and is used to determine the sequential numbering of a withholding tax certificate. The form number is defined in the vendor master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Recipient Type' + @sap.quickinfo : 'Type of Recipient' + RecipientType : String(2); + /** + * Numbered assigned by the relevant authorities for exemption from withholding tax. + * + * This number must be entered in the system as follows:In the vendor master record in the case of vendorsFor customers, in Customizing under the settings for withholding tax information for the company code per withholding tax type. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Exemption Number' + @sap.quickinfo : 'Exemption Certificate Number' + WithholdingTaxCertificate : String(25); + /** + * One or more "withholding tax codes" are assigned to each withholding tax type. One of the things these codes determine is the various percentage rates for the withholding tax type. + * + * Note that when processing a business transaction, no more than one withholding tax code can be assigned per withholding tax type. If the business transaction is subject to more than one withholding taxes, these must be represented in the system by defining various withholding tax types. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'W/Tax Code' + @sap.quickinfo : 'Withholding Tax Code' + WithholdingTaxCode : String(2); + /** + * Rate of exemption from withholding tax. + * + * Those persons/activities subject to withholding tax can be exempted from withholding tax up to the percentage rate you enter here. This exemption rate refers to the withholding tax amount itself and not to the whole amount liable to withholding tax (withholding tax base amount).The gross amount of an invoice is 100.00 and the withholding tax base amount is defined as gross. The withholding tax rate is 10% meaning that the withholding tax amount is 10.00. Given an exemption rate of 30%, the withholding tax amount is reduced to 7.00. + */ + @sap.label : 'Exemption Rate' + WithholdingTaxExmptPercent : Decimal(5, 2); + /** + * This is a number issued by the tax authorities per withholding tax type. + * + * This number must be specified in Customizing either:(a) As part of the withholding tax information defined for the company code, or(b) As part of the withholding tax information defined in the customer or vendor master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'W/tax number' + @sap.quickinfo : 'Withholding tax identification number' + WithholdingTaxNumber : String(16); + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); +}; + + diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/external/API_BUSINESS_PARTNER.edmx b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/external/API_BUSINESS_PARTNER.edmx new file mode 100644 index 000000000..5a6ddcc30 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/external/API_BUSINESS_PARTNER.edmx @@ -0,0 +1,3376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Internal key for identifying a Business Address Services address. + For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + + + + + Internal key for identifying a person in Business Address Services. + For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + + + + + + + Internet mail address, also called e-mail address. + Example: user.name@company.comThe Internet mail address is used to send mail via the Internet world-wide; the protocol used is SMTP (Simple Mail Transfer Protocol).The Internet mail address format is specified in various RFCs (Internet Request for Comment), including RFCs 821 and 822.This is not an IP address (192.56.30.6). + + + + + This field is generated by the system from the complete Internet mail address and is stored in table ADR6. + It contains the first 20 characters of the Internet mail address in normalized form, that is, without comment characters and converted into uppercase.The field cannot be maintained by the user or from an interface.The table ADR6 contains an index for this field.Using an Internet mail address, the corresponding key of table ADR6 and the owner of the address are determined (for example, business partner or user). + + + + + Additional information about the communication connection + You can maintain further information about the communication connection here. In the case of telephone numbers, for example, you can maintain the times at which the call recipient is available and those at which they are not, or you can specify whether the number is that of the secretary.The information is stored in table ADRT, regardless of language. + + + + + + + + + + + + Internal key for identifying a Business Address Services address. + For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + + + + + Internal key for identifying a person in Business Address Services. + For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + + + + + + If several addresses are maintained for one communication type, the user in the SAP System can be reached under one of these addresses. One address can be set as theStandard Address. + The standard address is used for the following functions:When sending using the SMTP nodein SAPconnect, the home address of the communication type used is the one set as the sender address. The recipient can see this address in the sender information and can also reply directly to this address. The standard address is also transferred and can be used for incoming status notifications, for example.When sending using an RFC node in SAPconnect, the standard address of the communication type used is the one set as the sender address. The structure defined in the case of the RFC does not permit another address to be transferred, so the standard address is used for incoming status notifications too.The SAP users have the addresses of their exchange P.O. boxes in their standard communication type 'Internet Mail' as the home address and their Internet address in the SAP system as their standard address. Example:Home address: Bernard.Brown@Company.comStandard address: Bernard.Brown@System.Company.comSending using an SMTP nodeThe home address of the communication type 'Internet Mail' (Bernard.Brown@Company.com) is used as the sender address. If a reply is sent to this address the user receives directly in the exchange postbox.Sending using the RFC nodeThe standard address of the communication type 'Internet Mail' (Bernard.Brown@System.Company.com) is used as the sender address. If a reply is sent to this address, it arrives back to the SAP system.Example using a mail system groupThe users should get all messages in their Microsoft Exchange postboxes. In the SAP system the mail system group is activated for this using the setting "Send Messages to the Home Address".The address settings of the SAP users remain unchanged:Home address: Bernard.Brown@Company.comStandard address: Bernard.Brown@System.Company.comSending using an SMTP nodeThe home address of the communication type 'Internet Mail' (Bernard.Brown@Company.com) is used as the sender address. If a reply is sent to this address the user receives directly in the exchange postbox.Sending using the RFC nodeThe standard address of the communication type 'Internet Mail' (Bernard.Brown@System.Company.com) is used as the sender address. If a reply is sent to this address it arrives back in the SAP system. It is then forwarded using the mail system group to the home address and the user gets it in the exchange postbox. + + + + + The country for the telephone number or fax number is maintained here. + This specification is used to determine the correct country code. A normalized form of the telephone number or fax number is then derived and stored in a field for a program-driven search.In most cases, the telephone number or fax number refers directly to an address.If this is the case, when a new number is created, the country of the address is proposed.If this is not the case (for example, with address-independent communication data for a business partner), the country from the user parameter LND is proposed (if it is maintained). If the user parameter LND is not maintained, the country of the company address assigned in the user master data is proposed.If the country of the address changes, the country of the corresponding telephone number and fax address is not changed automatically.Example: A business partner moves abroad.If the telephone number is for a permanent connection, the telephone number also changes when the business partner moves and has to be maintained again in the system.If the telephone number is for a mobile telephone and the number is retained, the original country for this telephone number also has to be retained and must not be changed automatically to the new country of the address. + + + + + Fax number, consisting of dialling code and number, but without country dialling code. + If the fax number consists of a company number and an extension, the extension must be entered in the field extension.Fax number, as it is to be dialled from within the same country.Enter the following for the number "01234/567-0":Fax: 01234/567Extension: 0Enter the following for the number "01234/567-891":Fax: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Fax: 012-345Extension: 678In the following cases, enter the complete number (without country dialing code) in the field Fax:No part of the number can be considered as an extension.You are not sure which part of the number can be considered as an extension. + + + + + Fax extension number + If the fax number consists of a company number and an extension, the extension must be entered here.Enter the extensionThe following rules apply for the format of telephone and fax numbers:The length of the entries in the field Telephone and Extension (Fax and Extension) cannot be more than 24 characters in total.Leading spaces are not allowed in the field Telephone or Fax or in the field Extension.Valid characters are:Numbers (0123456789)Letters (ABCDEFGHIJKLMNOPQRSTUVWXYZ)Following other characters: /, (, ), - *, # and " " (space), but not as a leading space.If an + is entered as the first character, the system checks whether the specified number starts with a country code. If so, a warning message is displayed because the country code is automatically determined by the system and should not be stored in the Telephone number (Fax number) field.If an & is entered as the first character, the automatic check and formatting of the telephone number (fax number), as well as the determination of the country code, is suppressed.Enter the following for the number "01234/567-0":Fax: 01234/567Extension: 0Enter the following for the number "01234/567-891":Fax: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Fax: 012-345Extension: 678In the following cases, enter the complete number (without country dialing code) in the field Fax:No part of the number can be considered as an extension.You are not sure which part of the number can be considered as an extension. + + + + + The content of this field is automatically calculated by the system based on fax number and country code components. + This field is therefore not to be filled when Business Address Services function modules are called. + + + + + Additional information about the communication connection + You can maintain further information about the communication connection here. In the case of telephone numbers, for example, you can maintain the times at which the call recipient is available and those at which they are not, or you can specify whether the number is that of the secretary.The information is stored in table ADRT, regardless of language. + + + + + + + + + + + + + + Internal key for identifying a Business Address Services address. + For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + + + + + Internal key for identifying a person in Business Address Services. + For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + + + + + + + + + Additional information about the communication connection + You can maintain further information about the communication connection here. In the case of telephone numbers, for example, you can maintain the times at which the call recipient is available and those at which they are not, or you can specify whether the number is that of the secretary.The information is stored in table ADRT, regardless of language. + + + + + + + + + + + + + + Internal key for identifying a Business Address Services address. + For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + + + + + Internal key for identifying a person in Business Address Services. + For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + + + + + + The country for the telephone number or fax number is maintained here. + This specification is used to determine the correct country code. A normalized form of the telephone number or fax number is then derived and stored in a field for a program-driven search.In most cases, the telephone number or fax number refers directly to an address.If this is the case, when a new number is created, the country of the address is proposed.If this is not the case (for example, with address-independent communication data for a business partner), the country from the user parameter LND is proposed (if it is maintained). If the user parameter LND is not maintained, the country of the company address assigned in the user master data is proposed.If the country of the address changes, the country of the corresponding telephone number and fax address is not changed automatically.Example: A business partner moves abroad.If the telephone number is for a permanent connection, the telephone number also changes when the business partner moves and has to be maintained again in the system.If the telephone number is for a mobile telephone and the number is retained, the original country for this telephone number also has to be retained and must not be changed automatically to the new country of the address. + + + + + If several addresses are maintained for one communication type, the user in the SAP System can be reached under one of these addresses. One address can be set as theStandard Address. + The standard address is used for the following functions:When sending using the SMTP nodein SAPconnect, the home address of the communication type used is the one set as the sender address. The recipient can see this address in the sender information and can also reply directly to this address. The standard address is also transferred and can be used for incoming status notifications, for example.When sending using an RFC node in SAPconnect, the standard address of the communication type used is the one set as the sender address. The structure defined in the case of the RFC does not permit another address to be transferred, so the standard address is used for incoming status notifications too.The SAP users have the addresses of their exchange P.O. boxes in their standard communication type 'Internet Mail' as the home address and their Internet address in the SAP system as their standard address. Example:Home address: Bernard.Brown@Company.comStandard address: Bernard.Brown@System.Company.comSending using an SMTP nodeThe home address of the communication type 'Internet Mail' (Bernard.Brown@Company.com) is used as the sender address. If a reply is sent to this address the user receives directly in the exchange postbox.Sending using the RFC nodeThe standard address of the communication type 'Internet Mail' (Bernard.Brown@System.Company.com) is used as the sender address. If a reply is sent to this address, it arrives back to the SAP system.Example using a mail system groupThe users should get all messages in their Microsoft Exchange postboxes. In the SAP system the mail system group is activated for this using the setting "Send Messages to the Home Address".The address settings of the SAP users remain unchanged:Home address: Bernard.Brown@Company.comStandard address: Bernard.Brown@System.Company.comSending using an SMTP nodeThe home address of the communication type 'Internet Mail' (Bernard.Brown@Company.com) is used as the sender address. If a reply is sent to this address the user receives directly in the exchange postbox.Sending using the RFC nodeThe standard address of the communication type 'Internet Mail' (Bernard.Brown@System.Company.com) is used as the sender address. If a reply is sent to this address it arrives back in the SAP system. It is then forwarded using the mail system group to the home address and the user gets it in the exchange postbox. + + + + + Telephone number, consisting of dialling code and number, but without country dialling code. + If the telephone number consists of a company number and an extension, the extension must be entered in the field extension.Telephone number, as it is dialled from within the country.For the number "01234/567-0" enter the following:Telephone: 01234/567Estension: 0For the number "01234/567-891" enter the following:Telephone: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Telepone: 012-345Extension: 678In the following cases enter the complete number (without country dialling code) in the field Telephone:No part of the number can be regarded as an extension.You are not sure which part of the number can be regarded as an extension. + + + + + Telephone extension number + If the telephone number consists of a company number and an extension, the extension should be entered here.Enter the extension.The following rules apply for the format of telephone and fax numbers:The length of the entries in the field Telephone and Extension (Fax and Extension) cannot be more than 24 characters in total.Leading spaces are not allowed in the field Telephone or Fax or in the field Extension.Valid characters are:Numbers (0123456789)Letters (ABCDEFGHIJKLMNOPQRSTUVWXYZ)Following other characters: /, (, ), - *, # and " " (space), but not as a leading space.If an + is entered as the first character, the system checks whether the specified number starts with a country code. If so, a warning message is displayed because the country code is automatically determined by the system and should not be stored in the Telephone number (Fax number) field.If an & is entered as the first character, the automatic check and formatting of the telephone number (fax number), as well as the determination of the country code, is suppressed.For the number "01234/567-0" enter the following:Telephone: 01234/567Estension: 0For the number "01234/567-891" enter the following:Telephone: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Telepone: 012-345Extension: 678In the following cases enter the complete number (without country dialling code) in the field Telephone:No part of the number can be regarded as an extension.You are not sure which part of the number can be regarded as an extension. + + + + + The content of this field is automatically calculated by the system based on the telephone number and country code components. + This field is therefore not to be filled when Business Address Services function modules are called. + + + + + This field specifies whether the telephone number is a mobile telephone number. + ' ' : The telephone number is a fixed-line telephone'1' : The telephone number is the standard fixed-line telephone'2' : The telephone nubmer is a mobile telephone'3' : The telephone number is the standard mobile telephoneEither the standard fixed-line telephone number or the standard mobile telephone number is also the standard telephone number (FLGDEFAULT = 'X').In older data sets, this field may have also have the value ' ' for the standard fixed-line telephone. In this case, however, FLGDEFAULT is always 'X'.In Customizing, you can specify whether the SMS-compatible indicator is to be proposed for new mobile telephone numbers created in dialog by choosing General Settings -> Set countries -> Define Mobile Telephone Attributes for each country. + + + + + Additional information about the communication connection + You can maintain further information about the communication connection here. In the case of telephone numbers, for example, you can maintain the times at which the call recipient is available and those at which they are not, or you can specify whether the number is that of the secretary.The information is stored in table ADRT, regardless of language. + + + + + + + + + + + + + + The business partner relationship number is an internal number that identifies the business partner relationship set. + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + + Internal key for identifying a Business Address Services address. + For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + + + + + Internal key for identifying a Business Address Services address. + For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + + + + + Additional address field which is printed above the Street line. + The Street address contains two lines above the street and two lines below the street.See Print the Street address. + + + + + Additional address field which is printed under the Street line. + The Street address has two lines above the street and two lines below the steet.See Print the Street address. + + + + + Time zone as part of an address. + The time zone is automatically determined by the system in address maintenance if time zone Customizing is maintained.It depends on the country and the region. (Region means state, province or county, depending on the country)The automatic determination is only made if there is no value in the time zone field. + + + + + Part of the address (c/o = care of) if the recipient is different from the occupant and the names are not similar (e.g. subtenants). + Put the country-specific code (e.g. c/o) in front of the name of the occupant. This is not automatically done in the print format, like the language-specific word "PO Box".John Smithc/o David BrownThis field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + + City name as part of the address. + The city name is saved redundantly in another database field in upper- case letters, for search help.If the Postal regional structure ('city file') is active, the city name is checked against the Cities defined in the regional structure. + + + + + Postal code that is assigned directly to one company (= company postal code = major customer postal code). + This field is used for countries where major companies are assigned their own postal code by the national post office.This postal code has to be entered in the field "Company Postal Code". Postal codes for group major customers, however, have to be entered in the field "PO Box Postal Code", since individual customers with a shared postal code for group major customers are differentiated by means of their PO box. + + + + + The country key contains information which the system uses to check entries such as the length of the postal code or bank account number. + The two-character ISO code in accordance with ISO 3166, which is delivered by SAP as a default, is usually used.It could also be the vehicle license plate country-code or a typical country key, for example, in Germany the Federal statistics office key.The country keys are determined at system installation in the global settings.The definition of the country key in the SAP system does not have to match political or government entities.Since the country key does not have to correspond to the ISO code in all installations, programs that differ according to certain values of the country key cannot query the country key T005-LAND1, but have to program based on the ISO code T005 INTCA. + + + + + Specifies the county’s name + This field is used to store the county’s name. You can enter the name of the county in this field. + + + + + The delivery service is part of the PO box address. + Some countries offer different services in addition to regular postal delivery and PO boxes, for example the Private Bag or Response Bag. If an address is related to one of these delivery services, the information about this particular delivery service has to be entered in the corresponding fields.In the field "Number of Delivery Service," the number of the Private Bag, Response Bag, or other relevant service has to be entered. Entering a number is not mandatory for each delivery service.For each address, either the information about the PO box or the information about the delivery service can be entered, but not both types of information at the same time.Mr PickeringPrivate Bag 106999Timaru 7942Delivery services will only be taken into account for address formatting in countries in which they are commonly used in addition to regular postal delivery and PO boxes, for example, in Australia, New Zealand, and the USA. In all other countries, these fields will not be taken into account for address formatting. + + + + + The delivery service is part of the PO box address. + Some countries offer different services in addition to regular postal delivery and PO boxes, for example the Private Bag or Response Bag. If an address is related to one of these delivery services, the information about this particular delivery service has to be entered in the corresponding fields.In the field "Type of Delivery Service," the type of the delivery service has to be entered.For each address, either the information about the PO box or the information about the delivery service can be entered, but not both types of information at the same time.Mr PickeringPrivate Bag 106999Timaru 7942Delivery services will only be taken into account for address formatting in countries in which they are commonly used in addition to regular postal delivery and PO boxes, for example, in Australia, New Zealand, and the USA. In all other countries, these fields will not be taken into account for address formatting. + + + + + City or District supplement + In some countries, this entry is appended with a hyphen to the city name by the automatic address formatting, other countries, it is output on a line of its own or (e.g. in the USA) not printed.See the examples in the Address Layout Key documentation. + + + + + Key for form of address text. + You can also define a form of address text in Customizing.The form of address text can be maintained in different languages. + + + + + This field contains the full name or formatted name of a party. + For organizations or document addresses, typically the fields Name1 and Name2 are concatenated.For persons the field contains the formatted name according to country specific rules. It corresponds e.g. to the content of the fields BUT000-NAME1_TEXT or ADRP-NAME_TEXT. + + + + + City of residence which is different from the postal city + In some countries, the residential city is required if it differs from the postal city.In the USA, the official street indexes, against which data can be checked, are based on the residential city, not the postal city, which may be different.It is the same in France, where a postally correct address must contain the residential city in a separate line above the postal city, if it differs from the postal city.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + House number as part of an address. + It is printed in the Street line.Other supplementary street information can be entered in the House number supplement or one of the Street2, Street3, Street4 or Street5 fields. See Print the Street address.A house number (e.g. 117) or a house number with supplement (e.g. 117a), or a house number range (e.g. 16-20), can be maintained in this field. + + + + + House number supplement as part of an address, e.g. + App. 17 orSuite 600.It is printed in the Street line.Further Street supplements can be put in one of the fields Street2, Street3, Street4 or Street5.See Print the Street address. + + + + + The language key indicates + - the language in which texts are displayed,- the language in which you enter texts,- the language in which the system prints texts. + + + + + PO Box number as part of an address. + Only enter the PO Box number in this field. The text "PO Box" is provided in the recipient language by the system when you print the address.When you print an address, the "Street address" and the "PO Box address" are distinguished. The print program determines which of them has priority if both are maintained in an address record.Besides the PO Box number, the PO Box address uses the following fields:PO Box postal code, if specified (otherwise the normal postal code)PO Box city, if specified (otherwise the normal city)PO Box region, if specified (otherwise the normal region)PO Box country, if specified (otherwise the normal country)If the address is a "PO Box" (without a number), do not fill the "PO Box" field. Select the "PO Box w/o Number" indicator instead.You can also enter a company postal code for organizational addresses, instead of a PO Box. A separate field is predefined for this entry.For general information and examples about address formatting, see the documentation on the Address Structure Key. + + + + + Different city for the PO Box as an address component. + The PO Box city can be entered here if it is different from the address city.If the address is only a PO Box address, enter the city in the normal city field.If the address contains two different city names for the address and the PO Box address, use this field. + + + + + Different PO Box country in address. + The PO Box country can be entered here, if it is different from the street address country.If the address only has a PO Box address, the country is in the normal country field.Use this field if the address has two different country values for the street address and the PO Box address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + Different Region for PO Box in an address. + Enter the PO Box Region here, if it differs from the street address region.If the address only has a PO Box address, the Region in in the normal Region field.Use this field if the address has two different Region values for the street address and the PO Box address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + PO Box address without PO Box number flag. + Only the word 'PO Box' is output in PO Box addresses without PO Box number.Set this flag for a PO Box address without PO Box number.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + The PO box lobby is part of the PO box address. + In some countries, entering a PO box, postal code and city is not sufficient to uniquely identify a PO box, because the same PO box number is assigned multiple times in some cities.Therefore, additional information might be required to determine the post office of the PO box in question. This information can be entered in the field "PO Box Lobby."Mr NellingPO Box 4099HighfieldTimaru 7942The PO box lobby will only be taken into account for address formatting in countries in which it is commonly used in addition to regular postal delivery and PO boxes, for example, in Canada or New Zealand. In all other countries, this field will not be taken into account for address formatting. + + + + + Postal code that is required for a unique assignment of the PO box. + This field is used for countries where a different postal code applies to mail that is sent to the PO box rather than to the street address of a particular business partner.Postal codes for group major customers also have to be entered in the field for the PO box postal code since individual customers with a shared postal code for group major customers are differentiated by means of the PO box. Postal codes for major customers (= company postal codes), however, are assigned to one customer only and have to be entered in the field 'Company Postal Code'. + + + + + Internal key for identifying a person in Business Address Services. + For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + + + + + Postal code as part of the address + If different postal codes are maintained for the PO Box and Street address of an address, this field contains the Street address postal code. + + + + + Communication method with which you can exchange documents and messages with a business partner. + In Business Address Services, you can specify a standard communication method that can be used by programs to determine the means of communication for sending messages.One business partner wants all messages by fax, another by e-mail.The application context can restrict the possible methods of communication. For example, invitations should perhaps only be sent by post because of enclosures, whereas minutes can be sent by post, fax or e-mail.Communication strategies can be defined for this purpose and applied in application contexts. + + + + + In some countries, the region forms part of the address. The meaning depends on the country. + The automatic address formatting function prints the region in addresses in the USA, Canada, Italy, Brazil or Australia, and the county in Great Britain.For more information, see the examples in the documentation on the Address Layout Key.Meaning of the regional code in ...Australia -> ProvinceBrazil -> StateCanada -> ProvinceGermany -> StateGreat Britain -> CountyItaly -> ProvinceJapan -> PrefectureSwitzerland -> CantonUSA -> State + + + + + Street name as part of the address. + The street name is saved, redundantly in upper case in another database field, for search help purposes.There are other fields for address parts which can be printed above or below the street. See Print the Street address.The house number and other supplements are usually maintained in their own fields. See Formatting the Street line. + + + + + Additional address field which is printed above the Street line. + The Street address contains two lines above the street and two lines below the street.See Print the Street address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + Additional address field which is printed below the Street line. + The Street address contains two lines above the street and two lines below the street.See Print the Street address. + + + + + Specifies the tax jurisdiction. + + + + + + Sales and distribution: + Regional zone of Goods recipient.Purchasing:Regional zone of supplier.You can define regional zones to suit the requirements of your own business and country.Sales and distributionthe system automatically proposes a suitable route by using the transportation zone of the goods recipient in combination with other information about the delivery, such as theCountries of origin and destinationShipping conditionsTransportation groupIn the USA, for example, you can define regional zones to correspond to the US postal zip codes. + + + + + + + + + + + + + + + + + + The business partner relationship number is an internal number that identifies the business partner relationship set. + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + + Identifies the function that a person has within a company. + This is a contact person attribute that you can define in Customizing.Personnel managerSecretary + + + + + Name of the department of a business partner for your internal usage. + The name given by the business partner to this particular department may differ from the name that you use. You can enter the name given by the business partner in the field company department.This is a contact person attribute that you can define in Customizing.For your purposes, the department name is "Sales". The business partner names the same department "Sales South". + + + + + Telephone number, consisting of dialling code and number, but without country dialling code. + If the telephone number consists of a company number and an extension, the extension must be entered in the field extension.Telephone number, as it is dialled from within the country.For the number "01234/567-0" enter the following:Telephone: 01234/567Estension: 0For the number "01234/567-891" enter the following:Telephone: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Telepone: 012-345Extension: 678In the following cases enter the complete number (without country dialling code) in the field Telephone:No part of the number can be regarded as an extension.You are not sure which part of the number can be regarded as an extension. + + + + + Telephone extension number + If the telephone number consists of a company number and an extension, the extension should be entered here.Enter the extension.The following rules apply for the format of telephone and fax numbers:The length of the entries in the field Telephone and Extension (Fax and Extension) cannot be more than 24 characters in total.Leading spaces are not allowed in the field Telephone or Fax or in the field Extension.Valid characters are:Numbers (0123456789)Letters (ABCDEFGHIJKLMNOPQRSTUVWXYZ)Following other characters: /, (, ), - *, # and " " (space), but not as a leading space.If an + is entered as the first character, the system checks whether the specified number starts with a country code. If so, a warning message is displayed because the country code is automatically determined by the system and should not be stored in the Telephone number (Fax number) field.If an & is entered as the first character, the automatic check and formatting of the telephone number (fax number), as well as the determination of the country code, is suppressed.For the number "01234/567-0" enter the following:Telephone: 01234/567Estension: 0For the number "01234/567-891" enter the following:Telephone: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Telepone: 012-345Extension: 678In the following cases enter the complete number (without country dialling code) in the field Telephone:No part of the number can be regarded as an extension.You are not sure which part of the number can be regarded as an extension. + + + + + Fax number, consisting of dialling code and number, but without country dialling code. + If the fax number consists of a company number and an extension, the extension must be entered in the field extension.Fax number, as it is to be dialled from within the same country.Enter the following for the number "01234/567-0":Fax: 01234/567Extension: 0Enter the following for the number "01234/567-891":Fax: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Fax: 012-345Extension: 678In the following cases, enter the complete number (without country dialing code) in the field Fax:No part of the number can be considered as an extension.You are not sure which part of the number can be considered as an extension. + + + + + Fax extension number + If the fax number consists of a company number and an extension, the extension must be entered here.Enter the extensionThe following rules apply for the format of telephone and fax numbers:The length of the entries in the field Telephone and Extension (Fax and Extension) cannot be more than 24 characters in total.Leading spaces are not allowed in the field Telephone or Fax or in the field Extension.Valid characters are:Numbers (0123456789)Letters (ABCDEFGHIJKLMNOPQRSTUVWXYZ)Following other characters: /, (, ), - *, # and " " (space), but not as a leading space.If an + is entered as the first character, the system checks whether the specified number starts with a country code. If so, a warning message is displayed because the country code is automatically determined by the system and should not be stored in the Telephone number (Fax number) field.If an & is entered as the first character, the automatic check and formatting of the telephone number (fax number), as well as the determination of the country code, is suppressed.Enter the following for the number "01234/567-0":Fax: 01234/567Extension: 0Enter the following for the number "01234/567-891":Fax: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Fax: 012-345Extension: 678In the following cases, enter the complete number (without country dialing code) in the field Fax:No part of the number can be considered as an extension.You are not sure which part of the number can be considered as an extension. + + + + + Internet mail address, also called e-mail address. + Example: user.name@company.comThe Internet mail address is used to send mail via the Internet world-wide; the protocol used is SMTP (Simple Mail Transfer Protocol).The Internet mail address format is specified in various RFCs (Internet Request for Comment), including RFCs 821 and 822.This is not an IP address (192.56.30.6). + + + + + A relationship may exist between two business partners. The business partner relationship category characterizes the features of the relationship. + A distinction is made between a one-way and an undirected business partner relationship category. In a one-way relationship category, the relationship extends from one partner to another, but not vice versa.Marriage (undirected)Employee (one-way)Contact person (one-way) + + + + + + + + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + + Business partner attribute, which you can use to distinguish between various addresses by defining the address usage for communication with business partners. + Maintain the usage types for addresses (address types) in Customizing.You can create a short description and a name for the address type.When maintaining business partners you can use the function address usage to assign business partner addresses to address types.If necessary, you can set the indicator for multiple use in Customizing.Correspondence addressDelivery address + + + + + Internal key for identifying a Business Address Services address. + For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + + + + + + Establishes which is the standard address for an address usage. + Several addresses per period can be assigned to an address usage.If this is the case, then this indicator controls which of the assigned addresses should be the standard address of the relevant usage. This is determined automatically when the address usage is accessed. + + + + + You can use authorization groups to stipulate which business partners a user is allowed to process. + Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + + + + + + + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + A document (such as an ID card or driver's license) or an entry in a system of records (such as a commercial register) whose key can be stored as an attribute for a business partner. + The identification type is for classifying identification numbers.You can define the identification types and their descriptions in Customizing.You can also specify for which business partner category an ID type should be valid.If necessary, assign the identification type to an Identification Category.You can only assign one identification type to an identification category. + + + + + Number that serves to identify a business partner, such as driver's license, or ID card number. + + + + + + Institution that adminsters or assigns an ID number. + + + + + + Date on which the ID number was registered or assigned by the appropriate authority. + + + + + + Country in which an ID number was assigned, or in which the number is valid. + + + + + + In some countries, the region forms part of the address. The meaning depends on the country. + The automatic address formatting function prints the region in addresses in the USA, Canada, Italy, Brazil or Australia, and the county in Great Britain.For more information, see the examples in the documentation on the Address Layout Key.Meaning of the regional code in ...Australia -> ProvinceBrazil -> StateCanada -> ProvinceGermany -> StateGreat Britain -> CountyItaly -> ProvinceJapan -> PrefectureSwitzerland -> CantonUSA -> State + + + + + This date marks the start of validity of an ID number. + + + + + + This date marks the end of validity of an ID number. + + + + + + You can use authorization groups to stipulate which business partners a user is allowed to process. + Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + + + + + + + + + + + + Describes an industry. + An industry is a classification of companies according to their main business activity. For example, you can use Commerce, Banking, Services, Industry, Healthcare, Public Sector, Media, and so on, as industries.You can define industries along with their descriptions in Customizing.Assign the industry key to an industry key system. + + + + + Serves to combine and categorize several industries into a group. + You can create different industry systems, each with its own catalog of industries, whereby an industry can be assigned to several industry systems.You have to select one industry system as the standard industry system. This is then automatically displayed in the initial screen for the maintenance of industry data.You can define an industry system along with its description in Customizing. You can assign several industry systems to a business partner.If you choose the button All Industry Systems, you can access all the industry systems defined in the Customizing using the input help. + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + Identifies the industry in an industry system that can be defined as the standard industry. + It is recommended that you define an industry within an industry system as the standard industry, because only the standard industries can be determined at the interfaces to BW or the APIs, for example.This means that even if only one industry exists within an industry system, it should be indicated as the standard industry as this this information cannot be determined otherwise. + + + + + + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. + + + + + + Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. + + + + + + Key for academic title. + You can define a key for an academic title in Customizing. + + + + + You can use authorization groups to stipulate which business partners a user is allowed to process. + Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + + + + + Category under which a business partner is classified. + You can distinguish between the following business partner categories:OrganizationNatural personGroup of natural persons or organizationsThe processing screens for the business partner categories are set up differently.So, for example, the screen for an organization contains the field Legal form, but this is not needed in the screen for a natural person. + + + + + + Classification assigned when creating a business partner. + Assign each business partner to a grouping when you create the business partner. The grouping determines the number range. You cannot change the assignment afterwards.You can define the groupings, their descriptions, the associated number range and other attributes in Customizing.You can define standard groupings for the internal and the external number assignment.For each grouping create a number range.When you create a business partner, the entry in the grouping field determines whether and how an entry is made in the business partner number field. + + + + + + + Correspondence language (written) for business partners in the 'Person' category. Maintain the correspondence language for business partners in the 'Organization' and 'Group' category with the address (communication). + When transferring data (direct input), make sure that for a'Person', the field 'LANGU_CORR' and for an'Organization' or "Group" the field 'LANGU'has an entry. + + + + + + + + + Key for form of address text. + You can also define a form of address text in Customizing.The form of address text can be maintained in different languages. + + + + + An industry sector is the term used to classify a company according to its main business activity. + You can assign an industry sector to business partners in the category 'Organization'RetailBanksServicesIndustryHealth servicePublic sectorMedia + + + + + Here you enter the first 7 digits of the international location number. + The International Location Number (ILN) is assigned (in Germany by the Centrale for Coorganisation GmbH)) when a company is founded. It consists of 13 digits, the last digit being the check digit. There are two categories of location numbers:Participants who only need an ILN to cleary and unmistakably identify themselves for communication with the business partner are given a category 1 ILN. This cannot be used to identify articles by means of EAN.Participants who wish to assign the location numbers for their own enterprise areas are given a category 2 ILN. For a category 2 ILN, digits 1 to 7 are described as basis number. This is used as basis for the creation of article numbers (EAN). + + + + + Here, you enter digits 8-12 of the 13-digit international location number. + The international location number (ILN) is assigned when establishing a company (by the "Zentrale für Coorganisation GmbH" in Germany). It consists of 13 digits, the last of which is the check digit. There are two types of international location numbers:Subscribers who only need one ILN to identify themselves in communication with the business partner are given an ILN of type 1. These cannot be used for identifying articles by means of EAN.Subscribers who need to assign location numbers for their own company areas are given an ILN of type 2. Positions 1 through 7 of the ILN type 2 are known as the basis number. This basis number forms the basis for article numbers (EAN). + + + + + + + Indicator through which a distinction between natural and legal persons can be made during tax reporting. + Is used in Italy and Mexico ,among other countries.Brasil: If the indicator is not set, 'CGC' is relevant in tax number 1. If the indicator is set, 'CPF' is relevant in tax number 2.Colombia: In the case of some natural persons, the NIT number does not have a check digit. In this case you should set this indicator and the check is deactivated. + + + + + + + Language for verbal communication with a business partner. + This language may differ from the language(s) defined for written correspondence. + + + + + + + + + Denotes certain legal norms that are of significance for the organization of a company. + For business partners in the category "Organization", you can state the legal form of the company. This is for information purposes only.Stock corporation (AG in Germany)Limited liability company (GmbH in Germany) + + + + + First name field for business partners in the Organization category. + + + + + + Second name field for business partners in the Organization category. + + + + + + Third name field for business partners in the Organization category. + + + + + + Fourth name field for business partners in the Organization category. + + + + + + Indicates the official registration of a company in the Commercial Register. + If a company is not officially registered in the Commercial Register, it has to use some type of text addition, such as foundation pending, when referring to the legal form. + + + + + Term for the end of bankruptcy proceedings. + This date also indicates that the company no longer exists. + + + + + Denotes the term that you define for a business partner, and via which you can restrict the search for a business partner in the business partner search or in the locator. + + + + + + Denotes the term that you define for a business partner, and via which you can restrict the search for a business partner in the business partner search or in the locator. + + + + + + + + + If the business partner is blocked centrally, certain activities cannot be executed. + + + + + + You can use the business partner type to group business partners according to your own criteria in Customizing (IMG). + In Customizing you can show or hide fields for data entry, depending on the requirements of the relevant business partner type.Select a business partner type. You can obtain help by pressing the F4 key. + + + + + + First name field for business partners in the Group category. + + + + + + Second name field for business partners in the Group category. + + + + + + Internal key for identifying the address for communication data that spans all addresses in Business Partner. + For more information on the significance and usage of the address number, see the documentation for Business Address Services (BAS). + + + + + The check digit is derived from a special check digit procedure from digits of the previous international location numbers. In this way, you can check whether the ILN entered is actually valid. + + + + + + + The name format rule country and the name format rule key together uniquely identify a formatting rule. + A country can have several formats which correspond to different rules. Formatting rules describe the format of a person name. + + + + + See Name format. + + + + + + States the complete name of a person. + The complete name is generally generated and saved by the Business Address Services (BAS) according to country-specific rules from the individual name components (without the form of address).If, during the formatting of an address, you want to use an alternative name, you can manually format the alternative name here. + + + + + Internal key for identifying a person in Business Address Services. + For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + + + + + Establishes if the business partner is meant to be archived. + If the indicator is set, the relevant business partner can be archived from the view of the business partner administration.If the check of the data to be archived shows, for example, that there are still active business transactions the archiving of the business partner data is prevented even if the indicator is set.If the indicator is not set, the business partner will not be taken into consideration during archiving. + + + + + Business partner number from an external system or a legacy system. + If the current business partner is known under a different number in an external system, you can store this number here for information purposes.Direct input gives you the option of maintaining a business partner by specifying the external business partner number. If you maintain business partner data in your legacy system, you can transmit changes made to business partners to the SAP system without having to know the SAP business partner number in the legacy system. + + + + + Company ID standard for the whole group. + + + + + + + + + + + + + + + + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + Internal key for identifying a Business Address Services address. + For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + + + + + + + You can use authorization groups to stipulate which business partners a user is allowed to process. + Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + + + + + + Additional address field which is printed above the Street line. + The Street address contains two lines above the street and two lines below the street.See Print the Street address. + + + + + Additional address field which is printed under the Street line. + The Street address has two lines above the street and two lines below the steet.See Print the Street address. + + + + + Time zone as part of an address. + The time zone is automatically determined by the system in address maintenance if time zone Customizing is maintained.It depends on the country and the region. (Region means state, province or county, depending on the country)The automatic determination is only made if there is no value in the time zone field. + + + + + Part of the address (c/o = care of) if the recipient is different from the occupant and the names are not similar (e.g. subtenants). + Put the country-specific code (e.g. c/o) in front of the name of the occupant. This is not automatically done in the print format, like the language-specific word "PO Box".John Smithc/o David BrownThis field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + + City name as part of the address. + The city name is saved redundantly in another database field in upper- case letters, for search help.If the Postal regional structure ('city file') is active, the city name is checked against the Cities defined in the regional structure. + + + + + Postal code that is assigned directly to one company (= company postal code = major customer postal code). + This field is used for countries where major companies are assigned their own postal code by the national post office.This postal code has to be entered in the field "Company Postal Code". Postal codes for group major customers, however, have to be entered in the field "PO Box Postal Code", since individual customers with a shared postal code for group major customers are differentiated by means of their PO box. + + + + + The country key contains information which the system uses to check entries such as the length of the postal code or bank account number. + The two-character ISO code in accordance with ISO 3166, which is delivered by SAP as a default, is usually used.It could also be the vehicle license plate country-code or a typical country key, for example, in Germany the Federal statistics office key.The country keys are determined at system installation in the global settings.The definition of the country key in the SAP system does not have to match political or government entities.Since the country key does not have to correspond to the ISO code in all installations, programs that differ according to certain values of the country key cannot query the country key T005-LAND1, but have to program based on the ISO code T005 INTCA. + + + + + Specifies the county’s name + This field is used to store the county’s name. You can enter the name of the county in this field. + + + + + The delivery service is part of the PO box address. + Some countries offer different services in addition to regular postal delivery and PO boxes, for example the Private Bag or Response Bag. If an address is related to one of these delivery services, the information about this particular delivery service has to be entered in the corresponding fields.In the field "Number of Delivery Service," the number of the Private Bag, Response Bag, or other relevant service has to be entered. Entering a number is not mandatory for each delivery service.For each address, either the information about the PO box or the information about the delivery service can be entered, but not both types of information at the same time.Mr PickeringPrivate Bag 106999Timaru 7942Delivery services will only be taken into account for address formatting in countries in which they are commonly used in addition to regular postal delivery and PO boxes, for example, in Australia, New Zealand, and the USA. In all other countries, these fields will not be taken into account for address formatting. + + + + + The delivery service is part of the PO box address. + Some countries offer different services in addition to regular postal delivery and PO boxes, for example the Private Bag or Response Bag. If an address is related to one of these delivery services, the information about this particular delivery service has to be entered in the corresponding fields.In the field "Type of Delivery Service," the type of the delivery service has to be entered.For each address, either the information about the PO box or the information about the delivery service can be entered, but not both types of information at the same time.Mr PickeringPrivate Bag 106999Timaru 7942Delivery services will only be taken into account for address formatting in countries in which they are commonly used in addition to regular postal delivery and PO boxes, for example, in Australia, New Zealand, and the USA. In all other countries, these fields will not be taken into account for address formatting. + + + + + City or District supplement + In some countries, this entry is appended with a hyphen to the city name by the automatic address formatting, other countries, it is output on a line of its own or (e.g. in the USA) not printed.See the examples in the Address Layout Key documentation. + + + + + Key for form of address text. + You can also define a form of address text in Customizing.The form of address text can be maintained in different languages. + + + + + This field contains the full name or formatted name of a party. + For organizations or document addresses, typically the fields Name1 and Name2 are concatenated.For persons the field contains the formatted name according to country specific rules. It corresponds e.g. to the content of the fields BUT000-NAME1_TEXT or ADRP-NAME_TEXT. + + + + + City of residence which is different from the postal city + In some countries, the residential city is required if it differs from the postal city.In the USA, the official street indexes, against which data can be checked, are based on the residential city, not the postal city, which may be different.It is the same in France, where a postally correct address must contain the residential city in a separate line above the postal city, if it differs from the postal city.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + House number as part of an address. + It is printed in the Street line.Other supplementary street information can be entered in the House number supplement or one of the Street2, Street3, Street4 or Street5 fields. See Print the Street address.A house number (e.g. 117) or a house number with supplement (e.g. 117a), or a house number range (e.g. 16-20), can be maintained in this field. + + + + + House number supplement as part of an address, e.g. + App. 17 orSuite 600.It is printed in the Street line.Further Street supplements can be put in one of the fields Street2, Street3, Street4 or Street5.See Print the Street address. + + + + + The language key indicates + - the language in which texts are displayed,- the language in which you enter texts,- the language in which the system prints texts. + + + + + PO Box number as part of an address. + Only enter the PO Box number in this field. The text "PO Box" is provided in the recipient language by the system when you print the address.When you print an address, the "Street address" and the "PO Box address" are distinguished. The print program determines which of them has priority if both are maintained in an address record.Besides the PO Box number, the PO Box address uses the following fields:PO Box postal code, if specified (otherwise the normal postal code)PO Box city, if specified (otherwise the normal city)PO Box region, if specified (otherwise the normal region)PO Box country, if specified (otherwise the normal country)If the address is a "PO Box" (without a number), do not fill the "PO Box" field. Select the "PO Box w/o Number" indicator instead.You can also enter a company postal code for organizational addresses, instead of a PO Box. A separate field is predefined for this entry.For general information and examples about address formatting, see the documentation on the Address Structure Key. + + + + + Different city for the PO Box as an address component. + The PO Box city can be entered here if it is different from the address city.If the address is only a PO Box address, enter the city in the normal city field.If the address contains two different city names for the address and the PO Box address, use this field. + + + + + Different PO Box country in address. + The PO Box country can be entered here, if it is different from the street address country.If the address only has a PO Box address, the country is in the normal country field.Use this field if the address has two different country values for the street address and the PO Box address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + Different Region for PO Box in an address. + Enter the PO Box Region here, if it differs from the street address region.If the address only has a PO Box address, the Region in in the normal Region field.Use this field if the address has two different Region values for the street address and the PO Box address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + PO Box address without PO Box number flag. + Only the word 'PO Box' is output in PO Box addresses without PO Box number.Set this flag for a PO Box address without PO Box number.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + The PO box lobby is part of the PO box address. + In some countries, entering a PO box, postal code and city is not sufficient to uniquely identify a PO box, because the same PO box number is assigned multiple times in some cities.Therefore, additional information might be required to determine the post office of the PO box in question. This information can be entered in the field "PO Box Lobby."Mr NellingPO Box 4099HighfieldTimaru 7942The PO box lobby will only be taken into account for address formatting in countries in which it is commonly used in addition to regular postal delivery and PO boxes, for example, in Canada or New Zealand. In all other countries, this field will not be taken into account for address formatting. + + + + + Postal code that is required for a unique assignment of the PO box. + This field is used for countries where a different postal code applies to mail that is sent to the PO box rather than to the street address of a particular business partner.Postal codes for group major customers also have to be entered in the field for the PO box postal code since individual customers with a shared postal code for group major customers are differentiated by means of the PO box. Postal codes for major customers (= company postal codes), however, are assigned to one customer only and have to be entered in the field 'Company Postal Code'. + + + + + Internal key for identifying a person in Business Address Services. + For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + + + + + Postal code as part of the address + If different postal codes are maintained for the PO Box and Street address of an address, this field contains the Street address postal code. + + + + + Communication method with which you can exchange documents and messages with a business partner. + In Business Address Services, you can specify a standard communication method that can be used by programs to determine the means of communication for sending messages.One business partner wants all messages by fax, another by e-mail.The application context can restrict the possible methods of communication. For example, invitations should perhaps only be sent by post because of enclosures, whereas minutes can be sent by post, fax or e-mail.Communication strategies can be defined for this purpose and applied in application contexts. + + + + + In some countries, the region forms part of the address. The meaning depends on the country. + The automatic address formatting function prints the region in addresses in the USA, Canada, Italy, Brazil or Australia, and the county in Great Britain.For more information, see the examples in the documentation on the Address Layout Key.Meaning of the regional code in ...Australia -> ProvinceBrazil -> StateCanada -> ProvinceGermany -> StateGreat Britain -> CountyItaly -> ProvinceJapan -> PrefectureSwitzerland -> CantonUSA -> State + + + + + Street name as part of the address. + The street name is saved, redundantly in upper case in another database field, for search help purposes.There are other fields for address parts which can be printed above or below the street. See Print the Street address.The house number and other supplements are usually maintained in their own fields. See Formatting the Street line. + + + + + Additional address field which is printed above the Street line. + The Street address contains two lines above the street and two lines below the street.See Print the Street address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + Additional address field which is printed below the Street line. + The Street address contains two lines above the street and two lines below the street.See Print the Street address. + + + + + Specifies the tax jurisdiction. + + + + + + Sales and distribution: + Regional zone of Goods recipient.Purchasing:Regional zone of supplier.You can define regional zones to suit the requirements of your own business and country.Sales and distributionthe system automatically proposes a suitable route by using the transportation zone of the goods recipient in combination with other information about the delivery, such as theCountries of origin and destinationShipping conditionsTransportation groupIn the USA, for example, you can define regional zones to correspond to the US postal zip codes. + + + + + Address number from an external system or a legacy system + If the current address has a different number in an external system, you can save this number here for information purposes.In direct input you are able to maintain an address for a business partner by stating the external address number. If your business partner data is maintained in a legacy system, you can thus transmit changes to a BP address to the SAP system without having to know the SAP address number in the legacy system. + + + + + + + + + + + + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + Key identifying a business partner's bank details. + Enter a bank details ID for each separate set of bank details for a business partner.Business Partner: H. MillerBD-ID Fin.institution Acct no. 0001 Chemical Bank, NYC 56234560002 Chemical Bank, NYC 56231220003 First Bank of Pittsburgh ...Business partner: T.Wolsey and Co.BD-ID Fin.institution Acct no.GIR0 Citibank, Charleston ...GIR1 Chemical Bank, NYC ... + + + + + Identifies the country in which the bank is based. + The country key determines according to which rules the remaining bank data (for example, bank number and bank account number) is checked. + + + + + The name under which the bank operates. + + + + + + The bank key (under which the bank data is stored in the appropriate country) is specified in this field. + The country-specific meaning of this bank key is specified when defining country key.Normally banks have a bank number, which then also appears in the control data of the bank.In certain countries the bank account number assumes this function; in such a case there would be no bank numbers, the bank details are then under the account number.For data medium exchange it can be useful to be able create banks for foreign business partners without a bank number, even if the country in question has bank numbers. In such cases the bank key can be assigned internally.If the bank data is under another key, such as the SWIFT code for example, numbers can also be assigned externally. + + + + + Uniquely identifies a bank throughout the world. + SWIFT stands for Society for Worldwide Interbank Financial Telecommunication.BIC stands for Bank Identifier Code.This globally unique code can be used in international payment transactions to identify the bank without the need to specify an address or bank number. Specification of the SWIFT code/BIC is mainly relevant for automatic payment transactions. + + + + + Brazil, France, Spain, Portugal and Italy + The field contains a check key for the combination bank number and bank account number.USAIn USA this field is used to differentiate between a savings and a current account (if no value is entered, the default value 01 is used).01 Current account02 Savings account03 Loan account04 General ledgerJapanIn Japan this field specifies the type of account. This information is is copied from the payment medium print program into payment medium. The following is an example of the account types used:01 FUTSU (similar to a savings account)02 TOUZA (similar to a current account)04 CHOCHIKU (similar to an investment account)09 Other types of bank accountsSouth AfricaIn South Africa this field specifies the type of account. The information entered here is forwarded to the bank that carries out the payment order. The following account types are permitted in ABC format:01 Current (Cheque) Account02 Savings Account03 Transmission Account04 Bond Account06 Subscription Share AccountArgentinaIn Argentina this field specifies the type of account:CC Current Account (Cuenta corriente)CA Saving Account (Caja de ahorro)CE Special Saving Account (Caja de ahorro especial)CS Salary Account (Cuenta sueldos)VenezuelaIn Venezuela this field specifies the type of account:CC Checking Account (Cuenta corriente)CA Saving Account (Cuenta de ahorro)CE Special Saving Account (Cuenta de ahorro especial)CS Salary Account (Cuenta sueldos)MexicoIn Mexico this field contains a two-digit key for classifying the bank account (for example, as a savings or current account). This key have different definitions, depending on the bank.NoteFor countries that are not listed here, this field can be used for account-specific information. + + + + + Here you can enter another name that the payment program can use if the name of the account holder is not the same as the name of the Business Partner. + + + + + + + + + A uniform standardized ID number for representing bank details that is in accordance with the ECBS (European Committee for Banking Standards). An IBAN has a maximum of 34 alphanumeric characters and is a combination of the following elements: + Country key of the bank (ISO code)Two-digit check numberCountry-specific account number (in Germany this consists of the bank number and account number, in France the bank number, account number and check key).The IBAN not only makes international payments easier, in some countries it has advantages for domestic payments as well. Depending on the country, it can mean advantages for value and fees.The IBAN can be maintained in parallel with the bank details but does not replace them. It is stored under the master data of the business partner and can then be used when creating the payment medium.Since it is only the bank that has the account that may generate the IBAN corresponding to an account number, the SAP system only generates a proposal. You can confirm or change this proposal. If no proposal is generated, enter the IBAN manually.An IBAN in Belgium may look like this:Electronic Form:BE62510007547061Printed form, as it would appear on an invoice:IBAN BE62 5100 0754 7061 + + + + + + This field contains the number under which the account is managed at the bank. + + + + + + Additional details for the bank details of the business partner. + In some countries the data for the bank details of the business partner (bank number, bank account number, name of the account holder) have to supplemented by other details in order to be able to use certain payment processes. This supplementary details are defined here.If additional data is required for the bank details for payment transactions in your country (see the following examples), enter the reference information.If for an automatic debit the bank requires the reference number of the collection authorization in Norway or Great Britain, specify this number here.In Great Britain when making payments to an account in a 'Building Society' you must specify which number payment recipient has. These details must be defined in the reference field, whereas the fields Bank Key and Account Number are to be used for the bank details of the 'Building Society'.In Great Britain when entering a building society account number, the name of the building society should also be maintained in the system. + + + + + States that the bank has collection authorization from the business partner for the account. + Set this indicator if the bank has collection authorization.Note for Accounts Receivable (FI-AR)If this indicator is not set, there is no bank collection.Note for Contract Accounts Receivable and Payable (FI-CA)This indicator is not relevant. + + + + + Name of the city as a part of the address. + + + + + + You can use authorization groups to stipulate which business partners a user is allowed to process. + Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + + + + + + + + + + + + + The business partner relationship number is an internal number that identifies the business partner relationship set. + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + + + States whether the relationship is a standard relationship. + If several relationships of the BP relationship category contact person have been defined for, you can set the indicator standard relationship for one of these relationships.A relationship that is marked as a standard relationship can be used whenA certain scenario automatically selects a contact personThe contact person responsible is not knownYou can give this indicator to only one business partner relationship of a BP relationship category for a particular period. Another relationship of the same relationship category can be indicated as the standard relationship only if the periods for the relationship do not overlap or coincide. + + + + + A relationship may exist between two business partners. The business partner relationship category characterizes the features of the relationship. + A distinction is made between a one-way and an undirected business partner relationship category. In a one-way relationship category, the relationship extends from one partner to another, but not vice versa.Marriage (undirected)Employee (one-way)Contact person (one-way) + + + + + + + + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + Function that a business partner takes on, depending on a business transaction. + You can define business partner roles along with their attributes in Customizing.You can create an alphanumeric, 6-digit key for the BP role. You can also choose a title as the short form and a description as the long form for the role text.Screen control in the dialog takes place by assigning a BP view.A program can access specific business partner roles for a business partner using thebusiness partner role category . The role categories are also in the TB003 table. + + + + + + + You can use authorization groups to stipulate which business partners a user is allowed to process. + Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + + + + + + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + Specifies the tax number category. + + + + + + Specifies the tax number. + + + + + + Specifies the tax number. + You can enter up to 60 characters in this field. + + + + + You can use authorization groups to stipulate which business partners a user is allowed to process. + Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + + + + + + + + + + Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. + + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + Indicates if the processing of billing documents is blocked for the customer in all sales areas (company-wide, for example). + You can define different kinds of block, according to the needs of your organization. You can, for example, automatically block the processing of all credit memos to a certain customer, pending manual approval. + + + + + Name with which the user who entered the master record was logged on in the R/3 System. + + + + + + Date on which the master record, or the part of the master record being viewed, was created. + + + + + + The account group is a classifying feature within customer master records. The account group determines: + in which number range the customer account number should be;whether the number is assigned by the user or by the system;which specifications are necessary or possible in the master record. + + + + + Specifies a classification of the customer (for example, classifies the customer as a bulk purchaser). + The classifications are freely definable according to the needs of your organization. + + + + + + + Indicates if delivery processing is blocked for the customer in all sales areas (company-wide, for example). + You can define different kinds of block, according to the needs of your organization. You can, for example, automatically block all deliveries to a certain customer for credit reasons. + + + + + Denotes a natural person. + In the following countries, the system needs to know whether the taxpayer is a legal or natural person so that it can check the tax numbers correctly:BrazilBulgariaColombiaCroatiaGreeceItalyMexicoPeruSloveniaThailandUkraineThe flag is also used in conjunction with the Statement of Payments to Natural Persons report, as used in the Czech Republic and in Slovakia. This report only covers customers and vendors for whom you have set this indicator.In South Korea, it is used in conjunction with the Generic Withholding Tax Reporting program. + + + + + Indicates if sales order processing is blocked for the customer in all sales areas (company-wide, for example). + If you block sales order processing, the block counts for the following partner functions of the customer:Sold-to partyShip-to partyPayerIf you want to process an order where the ship-to party differs from the sold-to party, and the ship-to party is blocked, you cannot process the order.You can define different kinds of block, according to the needs of your organization. You can, for example, automatically block all free of charge deliveries and credit memo requests for a certain customer, pending manual approval before further processing can take place. + + + + + Indicates that the account is blocked for posting for all company codes. + If you set this indicator, the system prevents users from posting items to this account and issues an error message to inform them that the account is blocked. + + + + + Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. + + + + + + If the customer or the vendor belongs to a group, you can enter a group key here. The group key is freely assignable. + If you create a matchcode using this group key, group evaluations are possible. + + + + + Account number of another master record in which the official address is stored. This address is used, for example, for tax reports to the tax authorities in Italy. + + + + + + An industry is a distinct group of companies with the same basic business activity. The industry key is used in selecting data for evaluations (for example, a vendor master data list). You can specify industries such as trade, banking, service, manufacturing, health care, public service, media and so on. + The industry field belongs to the general data area of customer and vendor master records. + + + + + Specifies the code that uniquely identifies the industry (or industries) of the customer. + Depending on the standards your organization uses (for example, Standard Industry Codes (SIC)), enter the appropriate code. You can assign more than one industry code to a customer by choosing Create more. + + + + + Specifies an additional code that identifies the industry (or industries) of the customer. + Depending on the standards your organization uses (for example, Standard Industry Codes (SIC)), enter the appropriate code. + + + + + Specifies an additional code that identifies the industry (or industries) of the customer. + Depending on the standards your organization uses (for example, Standard Industry Codes (SIC)), enter the appropriate code. + + + + + Specifies an additional code that identifies the industry (or industries) of the customer. + Depending on the standards your organization uses (for example, Standard Industry Codes (SIC)), enter the appropriate code. + + + + + Specifies an additional code that identifies the industry (or industries) of the customer. + Depending on the standards your organization uses (for example, Standard Industry Codes (SIC)), enter the appropriate code. + + + + + Here you enter the first 7 digits of the international location number. + The International Location Number (ILN) is assigned (in Germany by the Centrale for Coorganisation GmbH)) when a company is founded. It consists of 13 digits, the last digit being the check digit. There are two categories of location numbers:Participants who only need an ILN to cleary and unmistakably identify themselves for communication with the business partner are given a category 1 ILN. This cannot be used to identify articles by means of EAN.Participants who wish to assign the location numbers for their own enterprise areas are given a category 2 ILN. For a category 2 ILN, digits 1 to 7 are described as basis number. This is used as basis for the creation of article numbers (EAN). + + + + + Specifies a regional division according to the market categories created by the A. C. Nielsen company. + By allocating a Nielsen division, you can use the services of the Nielsen Institute to create a market analysis of your customers. + + + + + Classification of companies according to tax aspects. + + + + + + Specifies the tax number. + Enter the appropriate tax number:Country Tax NumberArgentina CUIT number or CUIL numberBelgium Enterprise numberBrazil CNPJ numberBulgaria Unified identification codeChile RUT numberChina VAT registration number (shui wu deng ji hao)Colombia NIT numberCroatia Legal persons: company identification numberNatural persons: JMBG numberCzech Republic DIC numberFrance SIRET numberGreece Personal IDHungary Tax numberItaly Fiscal codeKazakhstan RNN (obsolete)Mexico RFC numberNetherlands SI registration number (Aansluitnummer UWV) of chain- liability vendorNorway VAT numberPeru RUC numberPhilippines Taxpayer identification number (see below)Poland NIP numberPortugal NIF numberRomania Tax numberRussia INNSlovakia DIC numberSlovenia Tax numberSouth Korea Natural persons: Personal identification numberLegal persons: Corporation IDSpain NIF numberSwitzerland UID numberTaiwan - China GUI registration numberThailand Personal IDTurkey Name of business partner's tax officeUkraine Taxpayer identification numberUnited Kingdom Company registration numberUnited States Social security numberVenezuela RIF numberIn the Philippines, enter the taxpayer identification number with a V or N at the end, as follows:If the business partner is liable to VAT: 999-999-999-999VIf the business partner is not liable to VAT: 999-999-999-999N + + + + + Specifies the tax number. + Enter the appropriate tax number:Country Tax NumberArgentina NIP number or CM numberBelgium VAT numberBrazil CPF numberBulgaria Legal persons: tax numberNatural persons: personal IDCroatia OIB number Czech Republic ICO numberFrance SIREN numberGreece AFM numberIndia TINItaly VAT numberKazakhstan BC (Beneficiary Code)Netherlands BSN numberRussia OKPO codeSlovakia ICO numberSouth Korea VAT registration numberSweden Organization registration numberSwitzerland VAT numberTaiwan - China Tax registration numberUkraine Legal persons: USREOU numberNatural persons: SRNP numberTurkey Tax numberUnited Kingdom NI numberUnited States Employer identification numberVenezuela NIT number + + + + + Specifies the tax number. + Enter the tax number that applies:Country Tax numberArgentina Withholding agent numberBrazil State tax numberBulgaria Social security numberMexico CURP numberKazakhstan BINNetherlands Tax registration number (Loonbelastingnummer) of the chain-liability vendorRussia KPP numberThailand Tax ID Ukraine VAT registration number + + + + + Specifies the tax number. + Enter the appropriate tax number:Country Tax NumberBrazil Municipal tax numberKazakhstan IINRussia OFK number (for public bodies only) + + + + + Kazakhstan + Specifies the certificate of registration as VAT payer in the following format: XXXXXYYYYYYYZZZZZZZZ, where: XXXXX is the certificate serial number, YYYYYYY is the certificate number and ZZZZZZZZ is the date of certificate issue. + + + + + Taxes in Argentina: + The format and the check of tax number 1 depend on the two-digit tax number type.The tax number type is an identification type for tax in Argentina (for example, 80 for CUIT) and is used for the DGI tax report. + + + + + VAT registration number (VAT reg.no.) of the customer, vendor or your company code. + The VAT registration number is used within the EU for tax-exempt deliveries for the "EC sales list". The check rules are defined for each EU country and cannot be changed. + + + + + Indicates that all data in this master record is to be deleted. + To delete this data, you have to run the archiving program for Accounts Receivable or Payable. This program will archive all master records marked for deletion provided that there is no dependent data in them.Deletion flags can also be used in the program for deleting master data. You should, however, run this program only to delete test data prior to production startup. + + + + + + + + + + + + + Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. + + + + + + The company code is an organizational unit within financial accounting. + + + + + + Contains settings that control how the system handles differences between the invoice amount and the amount received from a customer or the amount paid to a supplier. A tolerance group is unique within a company code. + + + + + + This field contains the account number the company is listed under at the customer. + + + + + + Identification code for the accounting clerk. + The name of the accounting clerk defined by this identification code can be used in the payment program for correspondence and reporting (for example, open item lists). + + + + + + + + + Account number of the customer for whom automatic payment transactions are to be carried out.The account number is only needed if bank collections are not to be made via the customer who owes the receivables. The same applies to refunds of payables.The specification in this field only applies to this company code. There is another field in which you can enter an alternative payee for all company codes. If both fields are filled, the specification for the company code has priority. + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + Indicator which specifies at what intervals the collective invoices are to be created for the customer. + + + + + + Internal memo of the accounting department. + The memo serves only as information on special features of the customer/vendor. + + + + + This field contains the account number of the head office. + This account number is only specified for branch accounts. All postings for which the account number of the branch is specified, are automatically posted to the head office account. The account number of the branch affected is noted in the line items.No line items or balances are managed in the branch account. + + + + + Indicates that during automatic payment transactions clearing is made with the corresponding vendor account, and that during manual clearing procedures, the items of that vendor account are also selected. + To use this function in automatic payment transactions, you have toenter the vendor account number in the customer master record,enter the customer account number in the vendor master record, andselect the "Clearing with customer" indicator in the vendor master record.If you set this indicator, the system will also include items of the vendor account in customer dunning. + + + + + All bank data is determined using this key. + + + + + + Enter an interest calculation indicator here if the account is to be included in automatic interest calculation. + + + + + + The date in this field displays the last time the interest calculation program processed this account. This is generally the upper limit of the last interest run. + Generally, this date is automatically maintained by the program (batch input). A manual entry in this field should only be made if an error has occurred or when implementing the interest calculation. + + + + + Indicates that payment transactions and dunning notices are created for the branch. + Normally automatic payment transactions and dunning notices are created for the head office.NoteSelect this indicator only if this account is a head office account. + + + + + If this indicator is set, every customer/vendor open item is paid separately during automatic payment transactions. This means that open items are not grouped together for payment. + + + + + + Indicates the layout rule for the Allocation field in the document line item. + The system uses a standard sort sequence for displaying line items. Among other things, it sorts the items according to the content of the Allocation field. This field can be filled either manually or automatically (by the system) when a document line item is entered.For this purpose, the system requires rules that determine which information is to be taken from the document header or from the document line item and placed in the field. The rules can be stored in the master record of an account which enables you to determine the standard sort sequence on an account-specific basis.NoteField information from another document line item cannot be adopted into the field of a particular item. + + + + + Block key (enqueue key) that is used to block an open item or an account to payment transactions. + You can use the block key as described below.Automatic Payment TransactionsIn automatic payment transactions, the block takes effect when it is entered in the system as follows:In the master recordIn the documentIf you enter the block in the master record then all open items for this account are contained in the exception list.The following block keys have a special meaning in the master record:The block key * has the effect that all items of the account are skipped in automatic payment transactions.The block key + has the effect that all items are skipped in which a payment method was not entered explicitly.The block key A is always set automatically when a down payment is entered. Therefore, you must not delete the block key A or use it for other purposes.Whether a block key can be set or removed in payment proposal processing depends on the attribute Changeable in payment proposal of the block key.Manual PaymentsManual payments are only affected by a block key in the document if you set the attribute Blocked for manual payments in the block key.A block key that was set in the master record does not have any effect on manual payments. You can have the system issue a warning message in that case. To do so, you have to make system settings. Set up message 671 of work area F5 in message control accordingly. + + + + + List of payment methods which may be used in automatic payment transactions with this customer/vendor if you do not specify a payment method in the item to be paid. + If you do specify a particular payment method in the item to be paid, this specification has priority over the specifications in the master record. You may also specify payment methods in the item which are not listed in the master record. + + + + + Key for defining payment terms composed of cash discount percentages and payment periods. + It is used in sales orders, purchase orders, and invoices. Terms of payment provide information for:Cash managementDunning proceduresPayment transactionsData can be entered in the field for the terms of payment key in various ways as you enter a business transaction:In most business transactions, the system defaults the key specified in the master record of the customer/vendor in question.In some transactions (for example, credit memos), however, the system does not default the key from the master record. Despite this, you can use the key from the customer/vendor master record by entering "*" in the field.Regardless of whether or not a key is defaulted from the master record, you can manually enter a key during document entry at:item level in sales ordersheader level in purchase orders and invoicesMaster records have separate areas for Financial Accounting, Sales, and Purchasing. You can specify different terms of payment keys in each of these areas. When you then enter a business transaction, the application in question will use the key specified in its area of the master record. + + + + + This indicator specifies that the customer/vendor should be sent all payment advice information by EDI. + + + + + + Indicates that the account is blocked for posting in the specified company code. + If you set this indicator, the system prevents users from posting items to this account and issues an error message to inform them that the account is blocked. + + + + + The reconciliation account in G/L accounting is the account which is updated parallel to the subledger account for normal postings (for example, invoice or payment). + For special postings (for example, down payment or bill of exchange), this account is replaced by another account (for example, 'down payments received' instead of 'receivables').The replacement takes place due to the special G/L indicator which you must specify for these types of postings. + + + + + Indicator that the payment history of the customer is to be recorded. + The amount and number of payments are then recorded per calendar month, as well as the average days in arrears.Information about cash discount payments and net payments is recorded separately.The indicator should not be set for one-time accounts and accounts which are paid automatically (bank collection or bank bill in Germany, bill of exchange payment request in France).You can only carry out evaluation of the payment history, for example, with the report for customer evaluation with OI listing, if you have selected this field. + + + + + Name or identification code of the accounting clerk at the customer. + + + + + + Indicates that the company code data in this master record is to be deleted. + To delete this data, you have to run the archiving program for Accounts Receivable or Payable. This program will archive all master records marked for deletion provided that there is no dependent data in them.This deletion flag cannot be used in the program that deletes master data. You should, however, run this program only to delete test data prior to production startup. + + + + + In cash management, customers and vendors are allocated to planning groups by means of an entry made in the master record. + You can define these planning groups in Customizing or the Implementation Guide (you will need to ensure that they are all the same length). In order to improve the liquidity forecast display for major customers and vendors, it can be advisable to enter their account number as the planning group.For the planning groups themselves a naming convention should be set up to improve liquidity forecasting. In the following examples, the customer planning groups begin with an "R" for receipts, and the vendor planning groups begin with an "E" for expenses.R1 Customers paying by bank collectionR2 Other domestic customersR3 Customers abroadR4 Affiliated company customersR5 High risk customersR6 Major customersR7 Rental incomeR8 Repayment of loans...E1 Domestic vendorsE2 Vendors abroadE3 Affiliated company vendorsE4 Major vendorsE5 Personnel costsE6 TaxesE7 Investments... + + + + + With the key specified here, you can refer to known/negotiated leave. + + + + + + The value adjustment key controls the way the open items are processed during individual value adjustment. + + + + + + The account group is a classifying feature within customer master records. The account group determines: + in which number range the customer account number should be;whether the number is assigned by the user or by the system;which specifications are necessary or possible in the master record. + + + + + + + + + + + + + + Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. + + + + + + The company code is an organizational unit within financial accounting. + + + + + + The dunning area represents an organizational entity that is responsible for dunning. The dunning areas represent a sub-structure of the company codes. + If different responsibilities or different dunning procedures exist within a company code, you can set up corresponding dunning areas.All dunning notices are made separately according to dunning areas, and if necessary with different dunning procedures.The dunning area must be noted in the line items. As long as documents are copied from preliminary work areas (billing documents), the dunning area can be derived from details such as division or sales area, if necessary. + + + + + Key which reflects the reason for a dunning block indicator. + + + + + + Number that specifies how often an item or account has been dunned. + The business partner has received the dunning level from the last dunning run.If you use dunning areas, it is the dunning level that the business partner received from the last dunning run in the dunning area assigned.The dunning program sets the dunning level automatically when the customer or vendor receives a dunning notice. + + + + + This field contains the key for the dunning procedure to be used. + + + + + + Account number of the customer who is to be the recipient of the dunning letters. + The account number is only needed if dunning letters are not sent to the customer who owes the receivables. + + + + + Date on which the last dunning notice was made. + + + + + + Date on which a legal dunning procedure was initiated. + The printing of dunning notices in the legal dunning procedure generates an internal notice about any further account movements. A dunning notice is not created for the customer.If the Legal dunning procedure field in the master record contains a date, this means that the account is involved in a legal dunning procedure. The relationship between this date and the dunning date does not affect how the account is processed.The printing of account movements in the legal dunning procedure differs from the normal printing of dunning notices as follows:You must specify a separate form for your dunning procedure in Customizing. For more information, see Customizing (IMG) under Dunning Forms.The dunning program also displays text element 520 "Legal dunning procedure". This makes it possible to display the date of the legal dunning procedure from the master record.The program also displays the documents blocked for dunning and those with a payment method (automatic debit, bank direct debit).Although dunning notices are printed, the dunning level does not change in the master record or in the items. New dunning level = old dunning level.The program only updates the date of the last dunning run.Enter the date manually. + + + + + Identification code for the accounting clerk dealing with dunning letters. + Using this identification code, the accounting clerk whose name is printed on the dunning letters is determined.If this field is not filled, then the entry from the Accounting clerk field is used. + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + The account group is a classifying feature within customer master records. The account group determines: + in which number range the customer account number should be;whether the number is assigned by the user or by the system;which specifications are necessary or possible in the master record. + + + + + + + + + + + + + Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. + + + + + + An organizational unit responsible for the sale of certain products or services. The responsibility of a sales organization may include legal liability for products and customer claims. + You can assign any number of distribution channels and divisions to a sales organization. A particular combination of sales organization, distribution channel, and division is known as a sales area. + + + + + The way in which products or services reach the customer. Typical examples of distribution channels are wholesale, retail, or direct sales. + You can maintain information about customers and materials by sales organization and distribution channel. Within a sales organization you can deliver goods to a given customer through more than one distribution channel.You can assign a distribution channel to one or more sales organizations. If, for example, you have numerous sales organizations, each sales organization may use the "Wholesale" distribution channel.For each combination of sales organization and distribution channel, you can further assign one or more of the divisions that are defined for the sales organization. You can, for example, assign "Food" and "Non-food" divisions to the "Wholesale" distribution channel. A particular combination of sales organization, distribution channel, and division is known as a sales area. + + + + + A way of grouping materials, products, or services. The system uses divisions to determine the sales areas and the business areas for a material, product, or service. + A product or service is always assigned to just one division. From the point of view of sales and distribution, the use of divisions lets you organize your sales structure around groups of similar products or product lines. This allows the people in a division who process orders and service customers to specialize within a manageable area of expertise.If a sales organization sells food and non-food products through both retail and wholesaledistribution channels each distribution channel could then be further split into food and non-food divisions. + + + + + This field contains the account number your company is listed under at the customer or vendor. + + + + + + The authorization group enables you protect access to certain objects. + In order to carry out a specific activity, the user must have authorization for the combination of the activity and the authorization group. + + + + + Indicates if further billing activities are blocked for the customer. The block applies throughout the specified sales area. + If you enter a blocking indicator, billing that is already underway is continued. However, you cannot process the document further.Enter one of the values predefined for your system. If you want to block billing for a customer throughout an entire sales organization, you must enter a blocking indicator for each sales area in which the sales organization is defined.You can block billing for a customer if, for example, there are credit-related or legal problems to be resolved. + + + + + Indicates whether a sales order must be delivered completely in a single delivery or whether the order can be partially delivered and completed over a number of deliveries. + + + + + + Customer's currency for a sales area. This currency will be used to settle the customer's charges for the given sales organization. + + + + + + + The account assignment group to which the system automatically posts the sales document. + The system uses the account assignment group as one of the criteria during the automatic determination of revenue accounts.The system automatically proposes the account assignment group from the customer master record of the payer. You can change the default value in the sales document or the billing document. + + + + + Identifies a particular group of customers (for example, wholesale or retail) for the purpose of pricing or generating statistics. + + + + + + Key for defining payment terms composed of cash discount percentages and payment periods. + It is used in sales orders, purchase orders, and invoices. Terms of payment provide information for:Cash managementDunning proceduresPayment transactionsData can be entered in the field for the terms of payment key in various ways as you enter a business transaction:In most business transactions, the system defaults the key specified in the master record of the customer/vendor in question.In some transactions (for example, credit memos), however, the system does not default the key from the master record. Despite this, you can use the key from the customer/vendor master record by entering "*" in the field.Regardless of whether or not a key is defaulted from the master record, you can manually enter a key during document entry at:item level in sales ordersheader level in purchase orders and invoicesMaster records have separate areas for Financial Accounting, Sales, and Purchasing. You can specify different terms of payment keys in each of these areas. When you then enter a business transaction, the application in question will use the key specified in its area of the master record. + + + + + A grouping of customers who share the same pricing requirements. + You can define price groups according to the needs of your organization and create pricing records for each group. You can, for example, define a group of customers to whom you want to give the same kind of discount. You can assign a price group to an individual customer either in the customer master record or in the sales document.The system can propose the price group from the customer master record. You can change the proposed value manually in the sales document at both header and item level. + + + + + Determines which pricing procedure the system should apply when you create a sales document for the customer. + You can define different pricing procedures for your system. A pricing procedure determines the type and sequence of conditions that the system uses for pricing in, for example, a sales order. + + + + + Indicates if further delivery processing is blocked for the customer. The block applies throughout the specified sales area. + If you enter a blocking indicator, delivery processing that is already underway is continued. However, no new processing can take place.Enter one of the values predefined for your system. If you want to block delivery processing for a customer within a particular sales organization, you must enter a blocking indicator for each sales area in which the sales organization is defined.You can block delivery processing for a customer if, for example, there are credit-related or legal problems to be resolved. + + + + + The delivery priority assigned to an item. + You can assign delivery priority to either a particular material or to a combination of customer and material. When you process deliveries collectively, you can use delivery priority as one of the selection criteria. + + + + + Commonly used trading terms that comply with the standards established by the International Chamber of Commerce (ICC). + Incoterms specify internationally recognized procedures that the shipper and the receiving party must follow for the shipping transaction to be completed successfully.If goods are shipped through a port of departure, the appropriate Incoterm might be: FOB ("Free On Board"). You can provide further details (for example, the name of the port) in the secondary Incoterm field: FOB Boston, for example. + + + + + Provides additional information for the Incoterms. This field is only available for C-Clauses (if customized appropriately). Note the following for the incoterms versions below: + No Version:This field is disabledIncoterm Version 2000This field is disabled as part of standard delivery unless a customer decides to enable it by the way of Customizing for Sales and Distribution under Master Data -> Business Partners -> Customers -> Billing Document -> Incoterms -> Map Incoterms to Versions.Incoterm Version 2010For this version, the field represents:Sea and inland waterway transport - Port of DestinationAny mode of transport - Place of Destination2010 Incoterms are divided as follows:Group 1: Rules for any mode or modes of transport (including by vessel)Incoterms Incoterms Description Location 2CPT Carriage Paid To Place of DestinationCIP Carriage & Insurance Paid To Place of DestinationGroup 2: Rules for sea and inland waterwaysIncoterms Incoterms Description Location 2CFR Cost & Freight Port of DestinationCIF Cost Insurance & Freight Port of Destination + + + + + An incoterms version is an edition containing a list of international terms for transportation that is defined by the International Chamber of Commerce (ICC). + + + + + + Provides additional information for the primary Incoterm. For Incoterms 2010, this field represents: + 1. For sea and inland waterway transport - Port of Shipment2. For any mode of transport - Place of Delivery 2010Incoterms are divided as follows:Group 1: Rules for any mode or modes of transport (including by vessel)Incoterms Incoterms Description Location 1 EXW Ex Works Place of DeliveryFCA Free Carrier Place of DeliveryCPT Carriage Paid To Place of DestinationCIP Carriage & Insurance Paid To Place of DestinationDAF Delivered at Frontier Place of DeliveryDDP Delivered Duty Paid Place of DestinationDDU Delivered Duty Unpaid Place of DestinationGroup 2: Rules for sea and inland waterwaysIncoterms Incoterms Description Location 1 FAS Free Alongside Ship Port of ShipmentFOB Free On Board Port of ShipmentCFR Cost & Freight Port of DestinationCIF Cost Insurance & Freight Port of DestinationDEQ Delivered Eq Quay (Duty Paid) Port of DestinationDES Delivered Ex Ship Port of DestinationIf the primary incoterm is specified as FOB “Free on Board”, the second field provides details of the port from which the delivery leaves, such as FOB Boston. + + + + + Indicates that all data in the master record will be deleted for the specified sales area. Before the deletion is made, the system checks for dependent data that would prevent the deletion. + + + + + + Additional information for the primary Incoterm. + If the primary Incoterm is, for example, FOB ("Free on Board"), then the second field provides details of the port from which the delivery leaves (for example, "FOB Boston"). + + + + + Identifies the calendar that determines the schedule of billing dates for the customer. + If, for example, a customer wants to consolidate the invoices you send out, you can predefine the billing schedule in a calendar in the system. During billing, the system automatically proposes the appropriate billing date from the calendar.The system proposes the billing schedule from the customer master record of the payer. You can change the value manually in the sales document. + + + + + The probability (expressed as a percentage) of the customer confirming the inquiry or quotation item as part of a sales order. + The system combines the probability factors from the sales document type and from the customer master record of the sold-to party.If probability is 80% for the sales document type and 50% in the customer master record, the system combines the two values. In this case, the system takes 50% of 80% and proposes 40% for the item.The system proposes the probability. You can change the value manually for the item.You can generate requirements from quotations. Accordingly, the probability of quotation items affects how requirements are passed on. For example, a quotation for 100 pieces and a probability of 50% will generate requirements for 50 pieces. + + + + + Indicates whether you are allowed to combine orders during delivery processing. + The system proposes the indicator from the customer master record. You can change the value manually in the sales document at both header and item level. + + + + + Indicates if further sales order processing is blocked for the customer. The block applies throughout the specified sales area. + You can define blocks according to the needs of your organization. If you enter a blocking indicator, sales order processing that is already underway is continued. However, no new processing can occur.Enter one of the values predefined for your system. If you want to block sales order processing for a customer within a particular sales organization, you must enter a blocking indicator for each sales area in which the sale organization is defined.You can block sales order processing for a customer if, for example, there are credit-related or legal problems to be resolved. + + + + + Specifies whether the customer requires full or partial delivery for the item. + You use this field to control partial deliveries at the item level. If the customer allows partial delivery, you can choose from different partial delivery options. For example, you can specify whether the customer allows you to make one delivery attempt only on the requested delivery date or whether unlimited delivery attempts are possible.When partial delivery indicator 'D' is set, the order can never have status 'fully delivered'. You must complete each item by entering a reason for rejection. This could be applied to scheduling agreements, for example.You can enter a value in this field only if the customer allows partial deliveries for the entire sales document. + + + + + Identifies a price list or other condition type (for example, a surcharge or discount). + You can define price list types according to the needs of your own organization. Price list types can be grouped according to:the kind of price list (for example, wholesale or retail)the currency in which the price appearsthe number of the price list typeYou can use price list types to apply conditions during pricing or to generate statistics.In the customer master record, enter one of the values predefined for your system. The system proposes the value automatically during sales order processing. You can change the value manually in the sales document header. + + + + + A group of sales people who are responsible for processing sales of certain products or services. + By using sales groups you can designate different areas of responsibility within a sales office. When you generate sales statistics, you can use the sales group as one of the selection criteria.If sales office personnel service both retail and wholesale markets, you can assign a sales group to each market.You assign each salesperson to a sales group in his or her user master record. You assign each customer to a particular sales group in the customer's master record. + + + + + A physical location (for example, a branch office) that has responsibility for the sale of certain products or services within a given geographical area. + When you create sales statistics, you can use a sales office as one of the selection criteria. When you print out order confirmations, you can include the address of the sales office.You can assign each customer to a sales office in the customer master record.Within a sales office you can establish sales groups (for example, departments) with specific sales responsibilities. Each person who works in the sales office can be assigned to a sales group in his or her user master record. Each customer can also be assigned to a particular sales group in the customer master record. + + + + + General shipping strategy for the delivery of goods from the vendor to the customer. + You can define shipping conditions in your system which correspond to the requirements of your company. You can specify a shipping condition in the customer master and in the vendor master.Shipping point determination (outbound delivery):The loading group, the plant and the shipping condition determine the shipping point that will be proposed by the system.Route determination (outbound delivery):Apart from the country and the geographical region of the shipping point, the ship-to party and the transportation group, the shipping condition determines the route that the system proposes in the order for the delivery of the goods. In the delivery, the route proposal also takes the weight group into account.A particular customer always requires immediate delivery. You enter the appropriate shipping condition into the customer master record. This means that when you process orders for this customer, the system automatically proposes the express mail room as a shipping point and the quickest way to the airport as a route.If a shipping condition has been assigned to a sales document type in Customizing, this condition will be proposed by the system in the corresponding sales document. If there is no assignment, the system copies the relevant data from the corresponding customer master record of the sold-to party. You cannot change this value during delivery processing. The shipping condition will not be copied from the delivery into the shipment. The shipping condition is one of several criteria for selecting deliveries when you create a shipment. You can enter a shipping condition manually in the shipment where it only serves as a characteristic for grouping shipments. + + + + + Plant from which the goods should be delivered to the customer. + This plant is automatically copied into the sales order item as the default value.If there is no default value when you process the sales order item, enter a delivering plant.The value proposed in the item is eitherfrom the customer master record of the goods recipient, orfrom the material master recordThe system checks whether it can propose a value (and for your own plants, whether the material has been created in the plant). If the system can propose a value, the plant is copied to the sales order item where you can change it as required. + + + + + A geographical sales district or region. + Each customer can be assigned to a sales district. You can use sales districts to apply pricing conditions. When you want to generate sales statistics, you can use sales districts as a selection criteria.The system can propose a value from the customer master record of the sold-to party. You can change the value manually in the document at the header or item level. + + + + + Identifies the customer's factory calendar that is used during the processing of invoice lists. + An invoice list is a list of invoices (single or collective) that you create for the customer either periodically or on predefined dates. The periods and dates are defined in the customer's factory calendar. Typically, the recipient of an invoice list takes on the responsibility for collecting payments from numerous individual customers and receives a factoring or del credere discount for the service.If you want to create invoice lists for the customer, you must enter an identifier for a predefined factory calendar. + + + + + Key representing a type of exchange rate in the system. + You enter the exchange rate type to store different exchange rates.You can use the exchange rate type to define a buying rate, selling rate, or average rate for translating foreign currency amounts. You can use the average rate for the currency translation, and the bank buying and selling rates for valuation of foreign currency amounts. + + + + + Specifies a customer-defined group of customers. + You can define up to five different groups of customers, according to the needs of your organization. You specify the groups in the customer master record under "Additional data". If you assign a particular customer to one or more groups, the system automatically displays the groups in the header data of corresponding sales orders.You can define customer groups in Tables TVV1 through TVV5 and assign them to specific languages in Tables TVV1T through TVV5T. + + + + + Specifies a customer-defined group of customers. + You can define up to five different groups of customers, according to the needs of your organization. You specify the groups in the customer master record under "Additional data". If you assign a particular customer to one or more groups, the system automatically displays the groups in the header data of corresponding sales orders.You can define customer groups in Tables TVV1 through TVV5 and assign them to specific languages in Tables TVV1T through TVV5T. + + + + + Specifies a customer-defined group of customers. + You can define up to five different groups of customers, according to the needs of your organization. You specify the groups in the customer master record under "Additional data". If you assign a particular customer to one or more groups, the system automatically displays the groups in the header data of corresponding sales orders.You can define customer groups in Tables TVV1 through TVV5 and assign them to specific languages in Tables TVV1T through TVV5T. + + + + + Specifies a customer-defined group of customers. + You can define up to five different groups of customers, according to the needs of your organization. You specify the groups in the customer master record under "Additional data". If you assign a particular customer to one or more groups, the system automatically displays the groups in the header data of corresponding sales orders.You can define customer groups in Tables TVV1 through TVV5 and assign them to specific languages in Tables TVV1T through TVV5T. + + + + + Specifies a customer-defined group of customers. + You can define up to five different groups of customers, according to the needs of your organization. You specify the groups in the customer master record under "Additional data". If you assign a particular customer to one or more groups, the system automatically displays the groups in the header data of corresponding sales orders.You can define customer groups in Tables TVV1 through TVV5 and assign them to specific languages in Tables TVV1T through TVV5T. + + + + + This key identifies the customer payment guarantee procedure. + The customer payment guarantee procedure determines which payment guarantee procedure the system automatically uses when you create a sales document for the customer.In receivables risk management, the system determines the payment guarantee procedure taking into account:the key for the document payment guarantee procedure in the header for the sales document type.the customer payment guarantee procedure key in the customer master.You can define different payment guarantee procedures for your system. The payment guarantee procedure defines the type and sequence of forms of payment guarantee that the system assigns to the sales document items. + + + + + The account group is a classifying feature within customer master records. The account group determines: + in which number range the customer account number should be;whether the number is assigned by the user or by the system;which specifications are necessary or possible in the master record. + + + + + + + + + + + + + + + + + Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. + + + + + + An organizational unit responsible for the sale of certain products or services. The responsibility of a sales organization may include legal liability for products and customer claims. + You can assign any number of distribution channels and divisions to a sales organization. A particular combination of sales organization, distribution channel, and division is known as a sales area. + + + + + Specifies a distribution channel that you want to use as a reference for customer and material master data for other distribution channels. + You can specify one distribution channel as the source of customer and material master data for other distribution channels. You need then only to maintain the data in one place.Distrib.channel Ref.distrib.channel01 0102 0103 0104 04In this example, only distribution channels 01 and 04 have customer and material master data defined. Distribution channels 01, 02, and 03 share the master data that you defined for distribution channel 01. Distribution channel 04 has its own master data. When you create a sales order in distribution channel 03, the system checks the customer and material master data against the data defined for distribution channel 01. + + + + + A way of grouping materials, products, or services. The system uses divisions to determine the sales areas and the business areas for a material, product, or service. + A product or service is always assigned to just one division. From the point of view of sales and distribution, the use of divisions lets you organize your sales structure around groups of similar products or product lines. This allows the people in a division who process orders and service customers to specialize within a manageable area of expertise.If a sales organization sells food and non-food products through both retail and wholesaledistribution channels each distribution channel could then be further split into food and non-food divisions. + + + + + Identifies the country in which the delivery originates. + You can define the country key in a table. As a rule, it is a good idea to use the existing international standards for identifying vehicles from different countries (for example: USA = United States, I = Italy, and so on). The system uses the key tohelp determine the relevant taxes during pricingdetermine important country-specific standards (the length of postal codes and bank account numbers, for example) + + + + + Identifies the condition that the system uses to automatically determine country-specific taxes during pricing. + You can define one or more tax categories for each country. During sales order processing, the system applies the tax category according tothe geographical location of your delivering plant and the location of the customer receiving the goodstax classifications in the customer master record and the material master record.In the USA, for example, you can define tax categories for Federal Sales Tax and Federal Excise Tax. In the U.K., you can define a tax category for Value Added Tax (VAT). + + + + + Specifies the tax liability of the customer, based on the tax structure of the customer's country. + You can use the tax classification to specify, for example, whether a customer is liable for sales taxes, such as VAT or state sales taxes.During sales order processing, the system copies the tax classification from the tax information stored in thecustomer master record of the payer, if the payer is different from the sold-to party and the sales tax identification number is maintained for the payer.ship to party, if the sales tax identification number of the ship-to party is maintained.sold-to party, if none of the criteria for the payer or the ship-to party are met.During pricing, the system calculates any relevant taxes by taking the following factors into account:The tax classification of the customer and the materialThe country keys of the customer and the delivering plant + + + + + + + + + + + + Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. + + + + + + The company code is an organizational unit within financial accounting. + + + + + + This indicator is used to classify the different types of withholding tax. + Withholding tax types classify particular features of a withholding tax including:The time at which the withholding tax is postedThe basis on which the base amount is calculatedThe basis for accumulation (if applicable)Withholding tax types are to be distinguished from withholding tax codes, to which are allocated the withholding tax percentage rate example.Whether a withholding tax can be defined as an existing type by means of a new code, or if a new type needs to be defined will depend on the type of transaction (see below).Note that a business transaction can only be assigned one withholding tax code per withholding tax type. If the business transaction is subject to several withholding taxes simultaneously, these must be represented by different types.This is the case in Argentina for example, where up to four kinds of withholding tax per business transaction are possible. + + + + + One or more "withholding tax codes" are assigned to each withholding tax type. One of the things these codes determine is the various percentage rates for the withholding tax type. + Note that when processing a business transaction, no more than one withholding tax code can be assigned per withholding tax type. If the business transaction is subject to more than one withholding taxes, these must be represented in the system by defining various withholding tax types. + + + + + + Date from which: + The company code is obligated to withhold tax for the given withholding tax type.This date must be entered in Customizing under the withholding tax information for the company code.The customer is obligated to withhold tax for the withholding tax type.This date must be defined in the customer master record. + + + + + Date to which: + The company code is obligated to withhold tax for the withholding tax type.This date must be entered in Customizing under the withholding tax information for the company code.The customer is obigated to withhold tax for the withholding tax type. + + + + + This is a number issued by the tax authorities per withholding tax type. + This number must be specified in Customizing either:(a) As part of the withholding tax information defined for the company code, or(b) As part of the withholding tax information defined in the customer or vendor master record. + + + + + Numbered assigned by the relevant authorities for exemption from withholding tax. + This number must be entered in the system as follows:In the vendor master record in the case of vendorsFor customers, in Customizing under the settings for withholding tax information for the company code per withholding tax type. + + + + + Rate of exemption from withholding tax. + Those persons/activities subject to withholding tax can be exempted from withholding tax up to the percentage rate you enter here. This exemption rate refers to the withholding tax amount itself and not to the whole amount liable to withholding tax (withholding tax base amount).The gross amount of an invoice is 100.00 and the withholding tax base amount is defined as gross. The withholding tax rate is 10% meaning that the withholding tax amount is 10.00. Given an exemption rate of 30%, the withholding tax amount is reduced to 7.00. + + + + + Date from which withholding tax exemption applies. + + + + + + Date on which withholding tax exemption expires. + + + + + + Indicator used to classify different types of exemption from liability to a particular withholding tax. + These indicators can be defined per withholding tax type in the vendor master record. + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + + + + + + + + + + + Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. + + + + + + An organizational unit responsible for the sale of certain products or services. The responsibility of a sales organization may include legal liability for products and customer claims. + You can assign any number of distribution channels and divisions to a sales organization. A particular combination of sales organization, distribution channel, and division is known as a sales area. + + + + + The way in which products or services reach the customer. Typical examples of distribution channels are wholesale, retail, or direct sales. + You can maintain information about customers and materials by sales organization and distribution channel. Within a sales organization you can deliver goods to a given customer through more than one distribution channel.You can assign a distribution channel to one or more sales organizations. If, for example, you have numerous sales organizations, each sales organization may use the "Wholesale" distribution channel.For each combination of sales organization and distribution channel, you can further assign one or more of the divisions that are defined for the sales organization. You can, for example, assign "Food" and "Non-food" divisions to the "Wholesale" distribution channel. A particular combination of sales organization, distribution channel, and division is known as a sales area. + + + + + A way of grouping materials, products, or services. The system uses divisions to determine the sales areas and the business areas for a material, product, or service. + A product or service is always assigned to just one division. From the point of view of sales and distribution, the use of divisions lets you organize your sales structure around groups of similar products or product lines. This allows the people in a division who process orders and service customers to specialize within a manageable area of expertise.If a sales organization sells food and non-food products through both retail and wholesaledistribution channels each distribution channel could then be further split into food and non-food divisions. + + + + + The sequential number that the system applies when there is more than one partner for a particular partner function. + When you create a sales order for a particular customer, there may be more than one ship-to party defined. The different ship-to parties are numbered sequentially. + + + + + The abbreviated form of the name that identifies the partner function. + + + + + + + Sold-to party number sent in by the customer in delivery schedules. + The system uses this number to automatically determine the ship-to party. + + + + + Specifies a partner as the default for a particular partner function. + When you enter more than one partner for a particular partner function (for example, you define three different ship-to parties), you can select one partner as the default. During sales or purchasing processing, if you have defined multiple partners for a partner function, the system prompts you to choose just one partner. The system presents the default partner as the first choice in the pop-up window. + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + + + + + + Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. + + + + + + The account number of the vendor with whom automatic payment transactions are carried out. + The field is only needed if payments are not to be made directly to the vendor to whom the payable is owed. The same applies to bank collections of receivables.The specification in this field applies to all company codes. There is a further field in which every company code can enter an alternative payee separately. If both fields are filled, the company code specification has priority. + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + Name with which the user who entered the master record was logged on in the R/3 System. + + + + + + Date on which the master record, or the part of the master record being viewed, was created. + + + + + + Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. + + + + + + + Indicates that the account is blocked for posting for all company codes. + If you set this indicator, the system prevents users from posting items to this account and issues an error message to inform them that the account is blocked. + + + + + Indicates whether or not the supplier master record is blocked for all departments (that is, whether or not posting to this record is allowed at all). + + + + + + The account group is a classifying feature within vendor master records. The account group determines: + the number interval for the account number of the vendor,whether the number is assigned by the user or by the system,which specifications are necessary and/or possible in the master record. + + + + + + + VAT registration number (VAT reg.no.) of the customer, vendor or your company code. + The VAT registration number is used within the EU for tax-exempt deliveries for the "EC sales list". The check rules are defined for each EU country and cannot be changed. + + + + + + + Indicates that all data in this master record is to be deleted. + To delete this data, you have to run the archiving program for Accounts Receivable or Payable. This program will archive all master records marked for deletion provided that there is no dependent data in them.Deletion flags can also be used in the program for deleting master data. You should, however, run this program only to delete test data prior to production startup. + + + + + Specifies an additional master record in which the official address is stored. + This address is used in Italy for business transactions with the tax office in Italy. + + + + + An industry is a distinct group of companies with the same basic business activity. The industry key is used in selecting data for evaluations (for example, a vendor master data list). You can specify industries such as trade, banking, service, manufacturing, health care, public service, media and so on. + The industry field belongs to the general data area of customer and vendor master records. + + + + + Here you enter the first 7 digits of the international location number. + The International Location Number (ILN) is assigned (in Germany by the Centrale for Coorganisation GmbH)) when a company is founded. It consists of 13 digits, the last digit being the check digit. There are two categories of location numbers:Participants who only need an ILN to cleary and unmistakably identify themselves for communication with the business partner are given a category 1 ILN. This cannot be used to identify articles by means of EAN.Participants who wish to assign the location numbers for their own enterprise areas are given a category 2 ILN. For a category 2 ILN, digits 1 to 7 are described as basis number. This is used as basis for the creation of article numbers (EAN). + + + + + Here, you enter digits 8-12 of the 13-digit international location number. + The international location number (ILN) is assigned when establishing a company (by the "Zentrale für Coorganisation GmbH" in Germany). It consists of 13 digits, the last of which is the check digit. There are two types of international location numbers:Subscribers who only need one ILN to identify themselves in communication with the business partner are given an ILN of type 1. These cannot be used for identifying articles by means of EAN.Subscribers who need to assign location numbers for their own company areas are given an ILN of type 2. Positions 1 through 7 of the ILN type 2 are known as the basis number. This basis number forms the basis for article numbers (EAN). + + + + + The check digit is derived from a special check digit procedure from digits of the previous international location numbers. In this way, you can check whether the ILN entered is actually valid. + + + + + + Denotes a natural person. + In the following countries, the system needs to know whether the taxpayer is a legal or natural person so that it can check the tax numbers correctly:BrazilBulgariaColombiaCroatiaGreeceItalyMexicoPeruSloveniaThailandUkraineThe flag is also used in conjunction with the Statement of Payments to Natural Persons report, as used in the Czech Republic and in Slovakia. This report only covers customers and vendors for whom you have set this indicator.In South Korea, it is used in conjunction with the Generic Withholding Tax Reporting program. + + + + + Classification of companies according to tax aspects. + + + + + + Date up to which the certification of the QM-system is valid. + + + + + + If a QM system is maintained by the supplier, you can store a description of the QM system here. + If a material is activated for QM in procurement, the system initiates the following check whenever purchasing functions are carried out (for example, when a request for a quotation is made or if a purchase order is created):Whether the supplier's verified QM system, according to supplier master record or quality info-record (for a combination of supplier/material) meets the requirements for QM systems as specified in the material masterIn carrying out the check, the system relies on the defined assignments for target QM systems and actual QM systems in the Customizing application.If the check is unsuccessful, a warning message is issued when a request for quotation is initiated and an error message is issued for all other procurement activities. + + + + + If the customer or the vendor belongs to a group, you can enter a group key here. The group key is freely assignable. + If you create a matchcode using this group key, group evaluations are possible. + + + + + Key that determines which procurement functions (for example, request for quotation, purchase order, or goods receipt) should be blocked for quality reasons. + You can enter a block key in the:Supplier master recordIn this case, the supplier block applies to all materials and plants.Quality info record for QM in procurementIn this case, the supplier block applies to a single material and plant.A block for quality reasons applies only to those materials for which QM in procurement is active. + + + + + Specifies the tax number. + Enter the appropriate tax number:Country Tax NumberArgentina CUIT number or CUIL numberBelgium Enterprise numberBrazil CNPJ numberBulgaria Unified identification codeChile RUT numberChina VAT registration number (shui wu deng ji hao)Colombia NIT numberCroatia Legal persons: company identification numberNatural persons: JMBG numberCzech Republic DIC numberFrance SIRET numberGreece Personal IDHungary Tax numberItaly Fiscal codeKazakhstan RNN (obsolete)Mexico RFC numberNetherlands SI registration number (Aansluitnummer UWV) of chain- liability vendorNorway VAT numberPeru RUC numberPhilippines Taxpayer identification number (see below)Poland NIP numberPortugal NIF numberRomania Tax numberRussia INNSlovakia DIC numberSlovenia Tax numberSouth Korea Natural persons: Personal identification numberLegal persons: Corporation IDSpain NIF numberSwitzerland UID numberTaiwan - China GUI registration numberThailand Personal IDTurkey Name of business partner's tax officeUkraine Taxpayer identification numberUnited Kingdom Company registration numberUnited States Social security numberVenezuela RIF numberIn the Philippines, enter the taxpayer identification number with a V or N at the end, as follows:If the business partner is liable to VAT: 999-999-999-999VIf the business partner is not liable to VAT: 999-999-999-999N + + + + + Specifies the tax number. + Enter the appropriate tax number:Country Tax NumberArgentina NIP number or CM numberBelgium VAT numberBrazil CPF numberBulgaria Legal persons: tax numberNatural persons: personal IDCroatia OIB number Czech Republic ICO numberFrance SIREN numberGreece AFM numberIndia TINItaly VAT numberKazakhstan BC (Beneficiary Code)Netherlands BSN numberRussia OKPO codeSlovakia ICO numberSouth Korea VAT registration numberSweden Organization registration numberSwitzerland VAT numberTaiwan - China Tax registration numberUkraine Legal persons: USREOU numberNatural persons: SRNP numberTurkey Tax numberUnited Kingdom NI numberUnited States Employer identification numberVenezuela NIT number + + + + + Specifies the tax number. + Enter the tax number that applies:Country Tax numberArgentina Withholding agent numberBrazil State tax numberBulgaria Social security numberMexico CURP numberKazakhstan BINNetherlands Tax registration number (Loonbelastingnummer) of the chain-liability vendorRussia KPP numberThailand Tax ID Ukraine VAT registration number + + + + + Specifies the tax number. + Enter the appropriate tax number:Country Tax NumberBrazil Municipal tax numberKazakhstan IINRussia OFK number (for public bodies only) + + + + + Kazakhstan + Specifies the certificate of registration as VAT payer in the following format: XXXXXYYYYYYYZZZZZZZZ, where: XXXXX is the certificate serial number, YYYYYYY is the certificate number and ZZZZZZZZ is the date of certificate issue. + + + + + The tax number of the vendor at the responsible tax authority. + + + + + + Taxes in Argentina: + The format and the check of tax number 1 depend on the two-digit tax number type.The tax number type is an identification type for tax in Argentina (for example, 80 for CUIT) and is used for the DGI tax report. + + + + + This indicator controls the process of proof of delivery during the incoming goods process for inbound deliveries. Processing is activating by switching on this indicator in the supplier master and by switching on the corresponding indicator in the delivery item category. + There are the following different characteristics:' ': not relevant for POD'A': generally relevant for POD'B': only relevant for POD if differences(Difference between notified quantity and actual quantity received) + + + + + Tax calculation for Brazil: + The IPI tax value is split up for this vendor. 50% of the calculated IPI tax value is posted as deductible input tax, 50% is deducted from the inventory posting or posting to expense account. + + + + + + + + + + + + + Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. + + + + + + The company code is an organizational unit within financial accounting. + + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + + Block key (enqueue key) that is used to block an open item or an account to payment transactions. + You can use the block key as described below.Automatic Payment TransactionsIn automatic payment transactions, the block takes effect when it is entered in the system as follows:In the master recordIn the documentIf you enter the block in the master record then all open items for this account are contained in the exception list.The following block keys have a special meaning in the master record:The block key * has the effect that all items of the account are skipped in automatic payment transactions.The block key + has the effect that all items are skipped in which a payment method was not entered explicitly.The block key A is always set automatically when a down payment is entered. Therefore, you must not delete the block key A or use it for other purposes.Whether a block key can be set or removed in payment proposal processing depends on the attribute Changeable in payment proposal of the block key.Manual PaymentsManual payments are only affected by a block key in the document if you set the attribute Blocked for manual payments in the block key.A block key that was set in the master record does not have any effect on manual payments. You can have the system issue a warning message in that case. To do so, you have to make system settings. Set up message 671 of work area F5 in message control accordingly. + + + + + Indicates that the account is blocked for posting in the specified company code. + If you set this indicator, the system prevents users from posting items to this account and issues an error message to inform them that the account is blocked. + + + + + Identification code for the accounting clerk. + The name of the accounting clerk defined by this identification code can be used in the payment program for correspondence and reporting (for example, open item lists). + + + + + + + Name or identification code of the accounting clerk at the vendor. + + + + + + + List of payment methods which may be used in automatic payment transactions with this customer/vendor if you do not specify a payment method in the item to be paid. + If you do specify a particular payment method in the item to be paid, this specification has priority over the specifications in the master record. You may also specify payment methods in the item which are not listed in the master record. + + + + + Key for defining payment terms composed of cash discount percentages and payment periods. + It is used in sales orders, purchase orders, and invoices. Terms of payment provide information for:Cash managementDunning proceduresPayment transactionsData can be entered in the field for the terms of payment key in various ways as you enter a business transaction:In most business transactions, the system defaults the key specified in the master record of the customer/vendor in question.In some transactions (for example, credit memos), however, the system does not default the key from the master record. Despite this, you can use the key from the customer/vendor master record by entering "*" in the field.Regardless of whether or not a key is defaulted from the master record, you can manually enter a key during document entry at:item level in sales ordersheader level in purchase orders and invoicesMaster records have separate areas for Financial Accounting, Sales, and Purchasing. You can specify different terms of payment keys in each of these areas. When you then enter a business transaction, the application in question will use the key specified in its area of the master record. + + + + + Indicates that during automatic payment transactions, clearing is made with the corresponding customer account, and that during manual clearing procedures, the items of that customer account are also selected. + To use this function in automatic payment transactions, you have toenter the customer account number in the vendor master record,enter the vendor account number in the customer master record, andselect the "Clearing with vendor" indicator in the customer master record.If this indicator is set, items belonging to the customer account will be included in any dunning run. + + + + + Indicates that payment transactions and dunning notices are created for the branch. + Normally automatic payment transactions and dunning notices are created for the head office.NoteSelect this indicator only if this account is a head office account. + + + + + If this indicator is set, every customer/vendor open item is paid separately during automatic payment transactions. This means that open items are not grouped together for payment. + + + + + + This indicator specifies that the customer/vendor should be sent all payment advice information by EDI. + + + + + + All bank data is determined using this key. + + + + + + Number of days which usually pass until the vendor has cashed your check. + During automatic payment transactions, the system calculates the value date for check payments using this information and stores the date in the line item. The date is calculated as follows:Value date = posting date + check cashing timeIn Cash Management, the value date is used as information about the expected cash outflow. + + + + + Currency key for amounts in the system. + + + + + + Maximum amount which may be issued on a bill of exchange if it is to be used in payment transactions with the business partner. + The amount limit is taken into consideration in automatic payment transactions for payments by bill of exchange and bill of exchange payment requests. Several bill of exchange forms are created if the amount to be settled is higher than the maximum amount given here. Each of these bills of exchange is issued for the maximum amount or for a smaller amount.Amount limits for bills of exchange are used in Spain, for example. + + + + + This field contains the account number the company is listed under at the vendor. + + + + + + The reconciliation account in G/L accounting is the account which is updated parallel to the subledger account for normal postings (for example, invoice or payment). + For special postings (for example, down payment or bill of exchange), this account is replaced by another account (for example, 'down payments received' instead of 'receivables').The replacement takes place due to the special G/L indicator which you must specify for these types of postings. + + + + + Enter an interest calculation indicator here if the account is to be included in automatic interest calculation. + + + + + + The date in this field displays the last time the interest calculation program processed this account. This is generally the upper limit of the last interest run. + Generally, this date is automatically maintained by the program (batch input). A manual entry in this field should only be made if an error has occurred or when implementing the interest calculation. + + + + + This field contains the account number of the master record for the head office account. + You specify this account number only for branch accounts. Items that you post using the branch account number are automatically posted to the head office account. The system records the branch account number in the line items.Neither transactions nor balances are kept in the branch account. + + + + + The account number of the vendor with whom automatic payment transactions are to be carried out. + The field is only needed if payments are not to be made directly to the vendor to whom the payable is owed. The same applies to bank collections of receivables.The specification in this field applies only to the company code. There is a further field in which you can enter an alternative payee for each company code. If both fields are filled, the company code specified has priority. + + + + + Indicates the layout rule for the Allocation field in the document line item. + The system uses a standard sort sequence for displaying line items. Among other things, it sorts the items according to the content of the Allocation field. This field can be filled either manually or automatically (by the system) when a document line item is entered.For this purpose, the system requires rules that determine which information is to be taken from the document header or from the document line item and placed in the field. The rules can be stored in the master record of an account which enables you to determine the standard sort sequence on an account-specific basis.NoteField information from another document line item cannot be adopted into the field of a particular item. + + + + + Contains settings that control how the system handles differences between the invoice amount and the amount received from a customer or the amount paid to a supplier. A tolerance group is unique within a company code. + + + + + + US government requirement. + Date field in which to enter certification date for small companies run by women or minorities. This certificate must be renewed every two years. + + + + + Internal memo of the accounting department. + The memo serves only as information on special features of the customer/vendor. + + + + + In some countries, an additional country is needed for calculating or reporting withholding tax. + The calculation can depend on the payee's country.A particular country key can be required by law for reporting which may possibly be different to the key used in the address.Examples: Japan, USA (1042), Argentina + + + + + Indicates that the company code data in this master record is to be deleted. + To delete this data, you have to run the archiving program for Accounts Receivable or Payable. This program will archive all master records marked for deletion provided that there is no dependent data in them.This deletion flag cannot be used in the program that deletes master data. You should, however, run this program only to delete test data prior to production startup. + + + + + In cash management, customers and vendors are allocated to planning groups by means of an entry made in the master record. + You can define these planning groups in Customizing or the Implementation Guide (you will need to ensure that they are all the same length). In order to improve the liquidity forecast display for major customers and vendors, it can be advisable to enter their account number as the planning group.For the planning groups themselves a naming convention should be set up to improve liquidity forecasting. In the following examples, the customer planning groups begin with an "R" for receipts, and the vendor planning groups begin with an "E" for expenses.R1 Customers paying by bank collectionR2 Other domestic customersR3 Customers abroadR4 Affiliated company customersR5 High risk customersR6 Major customersR7 Rental incomeR8 Repayment of loans...E1 Domestic vendorsE2 Vendors abroadE3 Affiliated company vendorsE4 Major vendorsE5 Personnel costsE6 TaxesE7 Investments... + + + + + When incoming invoices are entered or when memos are entered in Financial Accounting (FI), the system checks whether an invoice or credit memo has already been entered for the same date. + Checking Logistics DocumentsThe system checks whether the invoice documents have already been entered in the Logistics invoice verification. For this, the system checks invoices that have been held or parked or that contain errors, or invoices that were entered for invoice verification in the background. The check is performed only if you specify the reference document number when you enter the invoices.When checking for duplicate invoices, the system compares the following specified characteristics:VendorCurrencyCompany CodeGross Invoice AmountReference Document NumberInvoice Document DateIf all of these characteristics are the same, the system issues a message for which you can change the message type in Customizing.When you enter credit memos or subsequent adjustments, the system does not check for duplicate invoices.Exception: The exception is the Argentina country version, where the system checks for duplicate invoices and credit memos.No message is issued if you enter a document that has previously been reversed.In Customizing for Logistics Invoice Verification under Incoming Invoice -> Set Check for Duplicate Invoices, you can specify that the following characteristics are not checked:Reference Document NumberInvoice Document DateCompany CodeHaving fewer attributes to check increases the likelihood that the system will find a duplicate invoice.Example:The following document has already been entered and posted:Reference Document Number 333Invoice Date: 4/28/2000Gross Invoice Amount 100.00Currency: EURVendor: SpencerCompany Code: ChicagoYou have set up the check for duplicate invoices as follows in Customizing:The characteristics Reference Document Number and Company Code are not activated. Consequently, these characteristics are not checked.Now you enter the following invoice:Reference Document Number 334Invoice Date: 4/28/2000Gross Invoice Amount 100.00Currency: EURVendor: SpencerCompany Code: FlagstaffResultBecause you entered a reference document when you entered the invoice, the system checks for duplicate invoices. Compared against the invoice entered earlier, the invoice just entered has different values in the characteristics Reference and Company Code. However, these characteristics are not checked due to the settings that you have made in Customizing. All other characteristics are the same. The system issues a message telling you that an invoice has been entered twice.If the characteristic "Reference Document Number" had been selected in Customizing, the system would have checked the reference document number and established that it was different from the invoice entered earlier, and it consequently would not have issued a message.Checking FI DocumentsThe system checks whether there are FI documents that were posted or parked with the Logistics invoice verification or with an FI invoice transaction. Depending on the entry in the Reference field, one of the following checks is performed:If a reference number was specified in the sequential invoice/credit memo, the system checks whether an invoice/credit memo has already been posted for which all the following attributes agree:Company CodeVendorCurrencyDocument DateReference NumberIf no reference number was specified in the sequential invoice/credit memo, the system checks whether an invoice/credit memo has already been posted for which all the following attributes agree:Company CodeVendorCurrencyDocument DateAmount in Document CurrencyIn Materials Management, the system applies the check for duplicate invoices for invoices only, not for credit memos. + + + + + + The account group is a classifying feature within vendor master records. The account group determines: + the number interval for the account number of the vendor,whether the number is assigned by the user or by the system,which specifications are necessary and/or possible in the master record. + + + + + + + + + + + + + + Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. + + + + + + The company code is an organizational unit within financial accounting. + + + + + + The dunning area represents an organizational entity that is responsible for dunning. The dunning areas represent a sub-structure of the company codes. + If different responsibilities or different dunning procedures exist within a company code, you can set up corresponding dunning areas.All dunning notices are made separately according to dunning areas, and if necessary with different dunning procedures.The dunning area must be noted in the line items. As long as documents are copied from preliminary work areas (billing documents), the dunning area can be derived from details such as division or sales area, if necessary. + + + + + Key which reflects the reason for a dunning block indicator. + + + + + + Number that specifies how often an item or account has been dunned. + The business partner has received the dunning level from the last dunning run.If you use dunning areas, it is the dunning level that the business partner received from the last dunning run in the dunning area assigned.The dunning program sets the dunning level automatically when the customer or vendor receives a dunning notice. + + + + + This field contains the key for the dunning procedure to be used. + + + + + + Account number of the vendor who is to receive the dunning notice. + Note:If an entry is not made in this field, the dunning notice is sent to the address of the vendor to be processed. + + + + + Date on which the last dunning notice was made. + + + + + + Date on which a legal dunning procedure was initiated. + The printing of dunning notices in the legal dunning procedure generates an internal notice about any further account movements. A dunning notice is not created for the customer.If the Legal dunning procedure field in the master record contains a date, this means that the account is involved in a legal dunning procedure. The relationship between this date and the dunning date does not affect how the account is processed.The printing of account movements in the legal dunning procedure differs from the normal printing of dunning notices as follows:You must specify a separate form for your dunning procedure in Customizing. For more information, see Customizing (IMG) under Dunning Forms.The dunning program also displays text element 520 "Legal dunning procedure". This makes it possible to display the date of the legal dunning procedure from the master record.The program also displays the documents blocked for dunning and those with a payment method (automatic debit, bank direct debit).Although dunning notices are printed, the dunning level does not change in the master record or in the items. New dunning level = old dunning level.The program only updates the date of the last dunning run.Enter the date manually. + + + + + Identification code for the accounting clerk dealing with dunning letters. + Using this identification code, the accounting clerk whose name is printed on the dunning letters is determined.If this field is not filled, then the entry from the Accounting clerk field is used. + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + The account group is a classifying feature within vendor master records. The account group determines: + the number interval for the account number of the vendor,whether the number is assigned by the user or by the system,which specifications are necessary and/or possible in the master record. + + + + + + + + + + + + + + + Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. + + + + + + Denotes the purchasing organization. + + + + + + Subdivision of a supplier's overall product range according to various criteria. + For each supplier sub-range:The master data is kept on a common basisCertain conditions applyIn the supplier master, you can create different purchasing data and different partner functions for each supplier sub-range.You can also maintain and change the conditions for each supplier sub-range. You assign a material to a supplier sub-range in the info record.In the supplier master, you can maintain different data for particular supplier sub-ranges, such as ordering addresses or terms of payment, for example.When creating a purchase order with a known supplier, different data is only determined if the supplier sub-range is entered in the initial screen.Your supplier Smith in Houston has two sub-ranges: paint and glue.All materials from the "paint" sub-range are ordered in Houston.You have maintained an alternative ordering address in Detroit for the "glue" sub-range.If you order materials from the "glue" sub-range, the supplier sub-range finds the Detroit ordering address. + + + + + Key uniquely identifying a plant. + + + + + + The abbreviated form of the name that identifies the partner function. + + + + + + The sequential number that the system applies when there is more than one partner for a particular partner function. + When you create a sales order for a particular customer, there may be more than one ship-to party defined. The different ship-to parties are numbered sequentially. + + + + + Specifies a partner as the default for a particular partner function. + When you enter more than one partner for a particular partner function (for example, you define three different ship-to parties), you can select one partner as the default. During sales or purchasing processing, if you have defined multiple partners for a partner function, the system prompts you to choose just one partner. The system presents the default partner as the first choice in the pop-up window. + + + + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + + + + + + + Alphanumeric key uniquely identifying the document. + With the supplier number, information from the supplier master record (such as the supplier's address and bank details) is copied into a purchasing document (such as a request for quotation or a purchase order).You can use the supplier number to keep track of requests for quotation, purchase orders and outline agreements. + + + + + Denotes the purchasing organization. + + + + + + Determines which calculation schema (pricing procedure) is to be used in purchasing documents containing this supplier number. + You can use the schema group to specify the calculation schema per purchasing organization or supplier. The relevant calculation schema is determined by reference to the schema group.The effect of this is that the conditions to be maintained in a purchasing document can differ depending on the relevant purchasing organization or supplier.If a calculation schema is only to be valid for certain purchasing organizations or suppliers, proceed as follows:Define the schema group for the purchasing organization or the supplier using the relevant function in the menu "Calculation schema -> Schema groups".Assign the schema group to the calculation schema via "Calculation schema -> Determine schema".Enter the schema group for the supplier in the supplier master records to which the calculation schema is to be assigned. Assign the schema group of the purchasing organization to the relevant purchasing organization using "Calculation schema -> Schema group -> Assign to purch. org.". + + + + + Indicates whether or not the supplier master record is earmarked for deletion. + + + + + + Commonly used trading terms that comply with the standards established by the International Chamber of Commerce (ICC). + Incoterms specify internationally recognized procedures that the shipper and the receiving party must follow for the shipping transaction to be completed successfully.If goods are shipped through a port of departure, the appropriate Incoterm might be: FOB ("Free On Board"). You can provide further details (for example, the name of the port) in the secondary Incoterm field: FOB Boston, for example. + + + + + Additional information for the primary Incoterm. + If the primary Incoterm is, for example, FOB ("Free on Board"), then the second field provides details of the port from which the delivery leaves (for example, "FOB Boston"). + + + + + An incoterms version is an edition containing a list of international terms for transportation that is defined by the International Chamber of Commerce (ICC). + + + + + + Provides additional information for the primary Incoterm. For Incoterms 2010, this field represents: + 1. For sea and inland waterway transport - Port of Shipment2. For any mode of transport - Place of Delivery 2010Incoterms are divided as follows:Group 1: Rules for any mode or modes of transport (including by vessel)Incoterms Incoterms Description Location 1 EXW Ex Works Place of DeliveryFCA Free Carrier Place of DeliveryCPT Carriage Paid To Place of DestinationCIP Carriage & Insurance Paid To Place of DestinationDAF Delivered at Frontier Place of DeliveryDDP Delivered Duty Paid Place of DestinationDDU Delivered Duty Unpaid Place of DestinationGroup 2: Rules for sea and inland waterwaysIncoterms Incoterms Description Location 1 FAS Free Alongside Ship Port of ShipmentFOB Free On Board Port of ShipmentCFR Cost & Freight Port of DestinationCIF Cost Insurance & Freight Port of DestinationDEQ Delivered Eq Quay (Duty Paid) Port of DestinationDES Delivered Ex Ship Port of DestinationIf the primary incoterm is specified as FOB “Free on Board”, the second field provides details of the port from which the delivery leaves, such as FOB Boston. + + + + + Provides additional information for the Incoterms. This field is only available for C-Clauses (if customized appropriately). Note the following for the incoterms versions below: + No Version:This field is disabledIncoterm Version 2000This field is disabled as part of standard delivery unless a customer decides to enable it by the way of Customizing for Sales and Distribution under Master Data -> Business Partners -> Customers -> Billing Document -> Incoterms -> Map Incoterms to Versions.Incoterm Version 2010For this version, the field represents:Sea and inland waterway transport - Port of DestinationAny mode of transport - Place of Destination2010 Incoterms are divided as follows:Group 1: Rules for any mode or modes of transport (including by vessel)Incoterms Incoterms Description Location 2CPT Carriage Paid To Place of DestinationCIP Carriage & Insurance Paid To Place of DestinationGroup 2: Rules for sea and inland waterwaysIncoterms Incoterms Description Location 2CFR Cost & Freight Port of DestinationCIF Cost Insurance & Freight Port of Destination + + + + + Indicator specifying that provision has been made for goods-receipt-based invoice verification for a purchase order item or invoice item. + + + + + + Number of calendar days needed to obtain the material or service if it is procured externally. + If you have different vendors for a material, you must specify an average value. The same applies if you order the material from a fixed vendor that has varying delivery times.If you use the SAP Retail System, the planned delivery time can be suggested from the vendor sub-range in the vendor master record. + + + + + Minimum value specified for purchase orders issued to the relevant supplier. + + + + + + Key for defining payment terms composed of cash discount percentages and payment periods. + It is used in sales orders, purchase orders, and invoices. Terms of payment provide information for:Cash managementDunning proceduresPayment transactionsData can be entered in the field for the terms of payment key in various ways as you enter a business transaction:In most business transactions, the system defaults the key specified in the master record of the customer/vendor in question.In some transactions (for example, credit memos), however, the system does not default the key from the master record. Despite this, you can use the key from the customer/vendor master record by entering "*" in the field.Regardless of whether or not a key is defaulted from the master record, you can manually enter a key during document entry at:item level in sales ordersheader level in purchase orders and invoicesMaster records have separate areas for Financial Accounting, Sales, and Purchasing. You can specify different terms of payment keys in each of these areas. When you then enter a business transaction, the application in question will use the key specified in its area of the master record. + + + + + Determines which date is to be used for price determination (pricing) purposes. + Enter the key for the desired date.If you choose the date of goods receipt, for example, a new price will be determined upon the arrival of the goods, causing the item to be revaluated at this time.NoteIf you have chosen the delivery date as the date for price determination and an item contains several delivery dates (i.e. has a delivery schedule), the first delivery date (the delivery date specified in the first schedule line) is taken. + + + + + Allows you to automatically generate purchase orders from purchase requisitions if the requisition has been assigned to a supplier (source of supply). + If you want to use automatic conversion, note the following additional conditions:In the case of purchase requisitions for materials, you should also select the indicator Autom.purch.ord. in the Purchasing view in the material master record.In the case of purchase requisitions for services, you should also select the indicator Automatic creation of POs for service PReqs in Customizing for Services by choosing:IMG -> MM -> External Services Management -> Source Determination and Default Values- for Client or- for Purchasing Organization + + + + + Key for the currency on which an order placed with a supplier is based. + + + + + + Key for a buyer or a group of buyers, who is/are responsible for certain purchasing activities. + Internally, the purchasing group is responsible for the procurement of a material or a class of materials.Externally, it is the medium through which contacts with the vendor are maintained. + + + + + Indicates whether or not the supplier master record is blocked for the purchasing organization for posting purposes. + + + + + + General shipping strategy for the delivery of goods from the vendor to the customer. + You can define shipping conditions in your system which correspond to the requirements of your company. You can specify a shipping condition in the customer master and in the vendor master.Shipping point determination (outbound delivery):The loading group, the plant and the shipping condition determine the shipping point that will be proposed by the system.Route determination (outbound delivery):Apart from the country and the geographical region of the shipping point, the ship-to party and the transportation group, the shipping condition determines the route that the system proposes in the order for the delivery of the goods. In the delivery, the route proposal also takes the weight group into account.A particular customer always requires immediate delivery. You enter the appropriate shipping condition into the customer master record. This means that when you process orders for this customer, the system automatically proposes the express mail room as a shipping point and the quickest way to the airport as a route.If a shipping condition has been assigned to a sales document type in Customizing, this condition will be proposed by the system in the corresponding sales document. If there is no assignment, the system copies the relevant data from the corresponding customer master record of the sold-to party. You cannot change this value during delivery processing. The shipping condition will not be copied from the delivery into the shipment. The shipping condition is one of several criteria for selecting deliveries when you create a shipment. You can enter a shipping condition manually in the shipment where it only serves as a characteristic for grouping shipments. + + + + + Means of classifying suppliers according to their significance to your company. + The indicator serves to assign the supplier to one of the categories A, B or C, in accordance with ABC analysis.'A' category suppliers, for instance, are those accounting for the greatest share of the company's total annual spend (in value terms). + + + + + This telephone number is maintained in the supplier master record and adopted in the purchasing document. + + + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + The account group is a classifying feature within vendor master records. The account group determines: + the number interval for the account number of the vendor,whether the number is assigned by the user or by the system,which specifications are necessary and/or possible in the master record. + + + + + + + + + + + + + Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. + + + + + + The company code is an organizational unit within financial accounting. + + + + + + This indicator is used to classify the different types of withholding tax. + Withholding tax types classify particular features of a withholding tax including:The time at which the withholding tax is postedThe basis on which the base amount is calculatedThe basis for accumulation (if applicable)Withholding tax types are to be distinguished from withholding tax codes, to which are allocated the withholding tax percentage rate example.Whether a withholding tax can be defined as an existing type by means of a new code, or if a new type needs to be defined will depend on the type of transaction (see below).Note that a business transaction can only be assigned one withholding tax code per withholding tax type. If the business transaction is subject to several withholding taxes simultaneously, these must be represented by different types.This is the case in Argentina for example, where up to four kinds of withholding tax per business transaction are possible. + + + + + Date from which withholding tax exemption applies. + + + + + + Date on which withholding tax exemption expires. + + + + + + Indicator used to classify different types of exemption from liability to a particular withholding tax. + These indicators can be defined per withholding tax type in the vendor master record. + + + + + + The type of recipient can be defined in the vendor master record. + It is used to group vendors together according to particular characteristics such as occupations that may be subject to the same withholding tax type, but which are required to pay different percentage rates (as defined by the withholding tax code).Application in ThailandThis corresponds to the official Thai form number (Phaw.Ngor.Daw) and is used to determine the sequential numbering of a withholding tax certificate. The form number is defined in the vendor master record. + + + + + Numbered assigned by the relevant authorities for exemption from withholding tax. + This number must be entered in the system as follows:In the vendor master record in the case of vendorsFor customers, in Customizing under the settings for withholding tax information for the company code per withholding tax type. + + + + + One or more "withholding tax codes" are assigned to each withholding tax type. One of the things these codes determine is the various percentage rates for the withholding tax type. + Note that when processing a business transaction, no more than one withholding tax code can be assigned per withholding tax type. If the business transaction is subject to more than one withholding taxes, these must be represented in the system by defining various withholding tax types. + + + + + Rate of exemption from withholding tax. + Those persons/activities subject to withholding tax can be exempted from withholding tax up to the percentage rate you enter here. This exemption rate refers to the withholding tax amount itself and not to the whole amount liable to withholding tax (withholding tax base amount).The gross amount of an invoice is 100.00 and the withholding tax base amount is defined as gross. The withholding tax rate is 10% meaning that the withholding tax amount is 10.00. Given an exemption rate of 30%, the withholding tax amount is reduced to 7.00. + + + + + This is a number issued by the tax authorities per withholding tax type. + This number must be specified in Customizing either:(a) As part of the withholding tax information defined for the company code, or(b) As part of the withholding tax information defined in the customer or vendor master record. + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + aggregate + groupby + filter + + + + + + + + + + + diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/notes-mashup.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/notes-mashup.cds new file mode 100644 index 000000000..6dbea08b1 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/notes-mashup.cds @@ -0,0 +1,32 @@ +using { API_BUSINESS_PARTNER } from './external/API_BUSINESS_PARTNER'; + +/** + * Simplified view on external addresses, which is used as an association target in Notes. + */ +entity my.bookshop.NoteableAddresses as select from API_BUSINESS_PARTNER.A_BusinessPartnerAddress mixin { + // bi-directional association + notes : Composition of many bookshop.Notes on notes.address.businessPartner = $projection.businessPartner and notes.address.ID = $projection.ID +} into { + key AddressID as ID, + key BusinessPartner as businessPartner, + @readonly Country as country, + @readonly CityName as city, + @readonly PostalCode as postalCode, + @readonly StreetName as street, + @readonly HouseNumber as houseNumber, + notes +}; + +/* + * Extend Notes with references to external Addresses. + */ +using { my.bookshop } from '../db/index'; +extend bookshop.Notes { + address: Association to bookshop.NoteableAddresses; +} + +using { NotesService } from './notes-service'; +extend service NotesService with { + @readonly + entity Addresses as projection on bookshop.NoteableAddresses +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/notes-service.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/notes-service.cds new file mode 100644 index 000000000..1a4fb617c --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/notes-service.cds @@ -0,0 +1,6 @@ +using my.bookshop from '../db/notes'; + +@path: 'notes' +service NotesService { + entity Notes as projection on bookshop.Notes; +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/pom.xml b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/pom.xml new file mode 100644 index 000000000..9035fbe85 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/pom.xml @@ -0,0 +1,284 @@ + + 4.0.0 + + + bookshop-parent + my + ${revision} + + + bookshop + jar + + bookshop + + + + + + com.sap.cds + cds-starter-spring-boot + + + + com.sap.cds + cds-adapter-odata-v4 + runtime + + + org.apache.commons + commons-collections4 + 4.4 + + + com.sap.cds + cds-feature-mt + 4.3.0 + + + com.sap.cds + sdm + 1.8.1-SNAPSHOT + + + com.sap.cds + cds-starter-cloudfoundry + runtime + + + com.sap.cds + cds-feature-xsuaa + + + com.sap.cloud.security.xsuaa + xsuaa-spring-boot-starter + + + + + + com.sap.cds + cds-starter-k8s + runtime + + + com.sap.cds + cds-feature-xsuaa + + + com.sap.cloud.security.xsuaa + xsuaa-spring-boot-starter + + + + + + com.sap.cds + cds-feature-enterprise-messaging + runtime + + + + com.sap.cds + cds-feature-remote-odata + runtime + + + + com.sap.cds + cds-feature-change-tracking + runtime + + + + + com.sap.cloud.sdk.cloudplatform + resilience + + + + com.sap.cloud.sdk + sdk-core + + + + com.sap.cloud.sdk.cloudplatform + connectivity-apache-httpclient4 + + + + + com.h2database + h2 + runtime + + + + org.xerial + sqlite-jdbc + runtime + + + + com.sap.hcp.cf.logging + cf-java-logging-support-servlet-jakarta + ${cf-java-logging-support.version} + + + + com.sap.hcp.cf.logging + cf-java-logging-support-logback + ${cf-java-logging-support.version} + + + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.security + spring-security-test + test + + + + org.springframework.boot + spring-boot-starter-webflux + test + + + + + org.springframework.boot + spring-boot-devtools + true + + + + + bookshop + + + + org.springframework.boot + spring-boot-maven-plugin + + false + + + + repackage + + repackage + + + exec + + + + + + + org.graalvm.buildtools + native-maven-plugin + + + + + com.sap.cds + cds-maven-plugin + ${cds.services.version} + + + cds.clean + + clean + + + + + cds.install-node + + install-node + + + ${cdsdk-global} + + + + + cds.install-dependencies + + npm + + + install @sap/cds-dk@${cds.install-cdsdk.version} @sap/cds-mtxs@^3 --no-save + + + + + cds.resolve + + resolve + + + + + cds.build + + cds + + + + build --for java --opts contentLocalizedEdmx=false + deploy --to h2 --with-mocks --dry > + "${project.basedir}/src/main/resources/schema.sql" + deploy --to h2 --dry > + "${project.basedir}/src/main/resources/schema-nomocks.sql" + compile srv/cat-service.cds -2 openapi --openapi:url /api/browse > + "${project.basedir}/src/main/resources/swagger/openapi.json" + + + + + + cds.generate + + generate + + + cds.gen + true + true + true + + + + + + + + + + + cdsdk-global + + true + + + + diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/review-service.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/review-service.cds new file mode 100644 index 000000000..60debda19 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/review-service.cds @@ -0,0 +1,30 @@ +using {my.bookshop as my} from '../db/index'; + +@path : 'review' +service ReviewService { + entity Reviews as projection on my.Reviews; + + @readonly + entity Books as projection on my.Books excluding { + createdBy, + modifiedBy + } + + @readonly + entity Authors as projection on my.Authors; + + // access control restrictions + annotate Reviews with @restrict : [ + { + grant : '*', + to : 'authenticated-user', + where : 'createdBy=$user' + }, + { + grant : '*', + to : 'admin', + } + ]; +} + +annotate ReviewService.Reviews with @odata.draft.enabled; diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/Application.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/Application.java new file mode 100644 index 000000000..d4ab598c7 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/Application.java @@ -0,0 +1,29 @@ +package my.bookshop; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; + +import com.sap.hcp.cf.logging.servlet.filter.RequestLoggingFilter; + +import jakarta.servlet.DispatcherType; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + @Bean + public FilterRegistrationBean loggingFilter() { + FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>(); + filterRegistrationBean.setFilter(new RequestLoggingFilter()); + filterRegistrationBean.setName("request-logging"); + filterRegistrationBean.addUrlPatterns("/*"); + filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST); + return filterRegistrationBean; + } + +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/MessageKeys.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/MessageKeys.java new file mode 100644 index 000000000..9f217eb93 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/MessageKeys.java @@ -0,0 +1,19 @@ +package my.bookshop; + +public class MessageKeys { + + public static final String QUANTITY_REQUIRE_MINIMUM = "quantity.require.minimum"; + public static final String BOOK_REQUIRE_STOCK = "book.require.stock"; + public static final String BOOK_ADDED_ORDER = "book.added.order"; + public static final String BOOK_MISSING = "book.missing"; + public static final String ORDERITEM_MISSING = "orderitem.missing"; + public static final String ORDER_MISSING = "order.missing"; + public static final String ORDER_INDRAFT = "order.indraft"; + public static final String BUPA_MISSING = "bupa.missing"; + + public static final String REVIEW_ADDED = "review.added"; + public static final String REVIEW_ADD_FORBIDDEN = "review.add.forbidden"; + public static final String ORDER_EXCEEDS_STOCK = "order.exceeds.stock"; + public static final String BOOK_IMPORT_FAILED = "book.import.failed"; + public static final String BOOK_IMPORT_INVALID_CSV = "book.import.invalid.csv"; +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/RatingCalculator.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/RatingCalculator.java new file mode 100644 index 000000000..0539c9059 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/RatingCalculator.java @@ -0,0 +1,64 @@ +package my.bookshop; + +import static cds.gen.my.bookshop.Bookshop_.BOOKS; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.OptionalDouble; +import java.util.stream.Stream; + +import org.springframework.stereotype.Component; + +import com.sap.cds.Result; +import com.sap.cds.ql.Select; +import com.sap.cds.ql.Update; +import com.sap.cds.services.persistence.PersistenceService; + +import cds.gen.my.bookshop.Books; +import cds.gen.my.bookshop.Reviews; + +/** + * Takes care of calculating the average rating of a book based on its review + * ratings. + */ +@Component +public class RatingCalculator { + + private PersistenceService db; + + RatingCalculator(PersistenceService db) { + this.db = db; + } + + /** + * Initializes the ratings for all existing books based on their reviews. + */ + public void initBookRatings() { + Result result = db.run(Select.from(BOOKS).columns(b -> b.ID())); + for (Books book : result.listOf(Books.class)) { + setBookRating(book.getId()); + } + } + + /** + * Sets the average rating for the given book. + * + * @param bookId + */ + public void setBookRating(String bookId) { + Result run = db.run(Select.from(BOOKS, b -> b.filter(b.ID().eq(bookId)).reviews())); + + Stream ratings = run.streamOf(Reviews.class).map(r -> r.getRating().doubleValue()); + BigDecimal rating = getAvgRating(ratings); + + db.run(Update.entity(BOOKS).byId(bookId).data(Books.RATING, rating)); + } + + static BigDecimal getAvgRating(Stream ratings) { + OptionalDouble avg = ratings.mapToDouble(Double::doubleValue).average(); + if (!avg.isPresent()) { + return BigDecimal.ZERO; + } + return BigDecimal.valueOf(avg.getAsDouble()).setScale(1, RoundingMode.HALF_UP); + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/CustomFeatureToggleProvider.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/CustomFeatureToggleProvider.java new file mode 100644 index 000000000..d4dfec9e7 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/CustomFeatureToggleProvider.java @@ -0,0 +1,30 @@ +package my.bookshop.config; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import com.sap.cds.services.request.FeatureTogglesInfo; +import com.sap.cds.services.request.ParameterInfo; +import com.sap.cds.services.request.UserInfo; +import com.sap.cds.services.runtime.FeatureTogglesInfoProvider; + +@Component +@Profile("cloud") // locally, feature toggles are configured directly with mock users +public class CustomFeatureToggleProvider implements FeatureTogglesInfoProvider { + + @Override + public FeatureTogglesInfo get(UserInfo userInfo, ParameterInfo parameterInfo) { + if (userInfo.getTenant() == null && userInfo.isSystemUser()) { + // technical provider user runs with all feature toggles + return FeatureTogglesInfo.all(); + } + + Map toggles = new HashMap<>(); + toggles.put("isbn", userInfo.hasRole("expert")); + toggles.put("discount", userInfo.hasRole("premium-customer")); + return FeatureTogglesInfo.create(toggles); + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/DestinationConfiguration.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/DestinationConfiguration.java new file mode 100644 index 000000000..94f796a4a --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/DestinationConfiguration.java @@ -0,0 +1,37 @@ +package my.bookshop.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.annotation.Profile; +import org.springframework.context.event.EventListener; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import com.sap.cloud.sdk.cloudplatform.connectivity.DefaultDestinationLoader; +import com.sap.cloud.sdk.cloudplatform.connectivity.DefaultHttpDestination; +import com.sap.cloud.sdk.cloudplatform.connectivity.DestinationAccessor; +import com.sap.cloud.sdk.cloudplatform.security.BasicCredentials; + +@Component +@Profile("mocked") +public class DestinationConfiguration { + + @Autowired + private Environment environment; + + @EventListener + void applicationReady(ApplicationReadyEvent ready) { + Integer port = environment.getProperty("local.server.port", Integer.class); + String destinationName = environment.getProperty("cds.remote.services.'[API_BUSINESS_PARTNER]'.destination.name"); + if(port != null && destinationName != null) { + DefaultHttpDestination httpDestination = DefaultHttpDestination + .builder("http://localhost:" + port) + .basicCredentials(new BasicCredentials("authenticated", "")) + .name(destinationName).build(); + + DestinationAccessor.prependDestinationLoader( + new DefaultDestinationLoader().registerDestination(httpDestination)); + } + } + +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/SwaggerResourceConfig.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/SwaggerResourceConfig.java new file mode 100644 index 000000000..af8b24b25 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/SwaggerResourceConfig.java @@ -0,0 +1,14 @@ +package my.bookshop.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class SwaggerResourceConfig implements WebMvcConfigurer { + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/swagger/**").addResourceLocations("classpath:/swagger/"); + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/WebSecurityConfig.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/WebSecurityConfig.java new file mode 100644 index 000000000..346a784fe --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/WebSecurityConfig.java @@ -0,0 +1,25 @@ +package my.bookshop.config; + +import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; + +@Configuration +@ConditionalOnWebApplication +@EnableWebSecurity +@Order(1) +public class WebSecurityConfig { + + @Bean + public SecurityFilterChain configure(HttpSecurity http) throws Exception { + return http.securityMatchers(s -> s.requestMatchers(antMatcher("/actuator/health"), antMatcher("/swagger/**"))) // + .csrf(c -> c.disable()).authorizeHttpRequests(a -> a.anyRequest().permitAll()) + .build(); + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceAddressHandler.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceAddressHandler.java new file mode 100644 index 000000000..6d113f231 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceAddressHandler.java @@ -0,0 +1,154 @@ +package my.bookshop.handlers; + +import static cds.gen.adminservice.AdminService_.ADDRESSES; + +import java.time.Duration; +import java.util.Optional; +import java.util.stream.Stream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import com.sap.cds.Result; +import com.sap.cds.ql.CQL; +import com.sap.cds.ql.Insert; +import com.sap.cds.ql.Predicate; +import com.sap.cds.ql.Select; +import com.sap.cds.ql.Upsert; +import com.sap.cds.ql.cqn.CqnSelect; +import com.sap.cds.ql.cqn.Modifier; +import com.sap.cds.services.ErrorStatuses; +import com.sap.cds.services.EventContext; +import com.sap.cds.services.ServiceException; +import com.sap.cds.services.cds.CdsReadEventContext; +import com.sap.cds.services.cds.CqnService; +import com.sap.cds.services.draft.DraftService; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.Before; +import com.sap.cds.services.handler.annotations.On; +import com.sap.cds.services.handler.annotations.ServiceName; +import com.sap.cds.services.persistence.PersistenceService; +import com.sap.cloud.sdk.cloudplatform.resilience.ResilienceConfiguration; +import com.sap.cloud.sdk.cloudplatform.resilience.ResilienceConfiguration.TimeLimiterConfiguration; +import com.sap.cloud.sdk.cloudplatform.resilience.ResilienceDecorator; + +import cds.gen.adminservice.Addresses; +import cds.gen.adminservice.Addresses_; +import cds.gen.adminservice.AdminService_; +import cds.gen.adminservice.Orders; +import cds.gen.api_business_partner.ApiBusinessPartner; +import cds.gen.api_business_partner.ApiBusinessPartner_; +import cds.gen.api_business_partner.BusinessPartnerChangedContext; +import my.bookshop.MessageKeys; + +/** + * Custom handler for the Admin Service Addresses, which come from a remote S/4 System + */ +@Component +@ServiceName(AdminService_.CDS_NAME) +public class AdminServiceAddressHandler implements EventHandler { + + private final static Logger logger = LoggerFactory.getLogger(AdminServiceAddressHandler.class); + + // We are mashing up the AdminService with two other services... + private final PersistenceService db; + private final ApiBusinessPartner bupa; + + AdminServiceAddressHandler(PersistenceService db, @Qualifier(ApiBusinessPartner_.CDS_NAME) ApiBusinessPartner bupa) { + this.db = db; + this.bupa = bupa; + } + + // Delegate ValueHelp requests to S/4 backend, fetching current user's addresses from there + @On(entity = Addresses_.CDS_NAME) + public void readAddresses(CdsReadEventContext context) { + if(context.getCqn().ref().segments().size() != 1) { + return; // no value help request + } + + // add BusinessPartner where condition + String businessPartner = context.getUserInfo().getAttributeValues("businessPartner").stream().findFirst() + .orElseThrow(() -> new ServiceException(ErrorStatuses.FORBIDDEN, MessageKeys.BUPA_MISSING)); + + CqnSelect select = CQL.copy(context.getCqn(), new Modifier() { + + public Predicate where(Predicate original) { + Predicate where = CQL.get(Addresses.BUSINESS_PARTNER).eq(businessPartner); + if(original != null) { + where = original.and(where); + } + return where; + } + + }); + + // using Cloud SDK resilience capabilities.. + ResilienceConfiguration config = ResilienceConfiguration.of(AdminServiceAddressHandler.class) + .timeLimiterConfiguration(TimeLimiterConfiguration.of(Duration.ofSeconds(10))); + + context.setResult(ResilienceDecorator.executeSupplier(() -> { + // ..to access the S/4 system in a resilient way.. + logger.info("Delegating GET Addresses to S/4 service"); + return bupa.run(select); + }, config, (t) -> { + // ..falling back to the already replicated addresses in our own database + logger.warn("Falling back to already replicated Addresses"); + return db.run(select); + })); + } + + // Replicate chosen addresses from S/4 when filling orders + @Before(event = { CqnService.EVENT_CREATE, CqnService.EVENT_UPDATE, DraftService.EVENT_DRAFT_PATCH }) + public void patchAddressId(EventContext context, Stream orders) { + String businessPartner = context.getUserInfo().getAttributeValues("businessPartner").stream().findFirst() + .orElseThrow(() -> new ServiceException(ErrorStatuses.FORBIDDEN, MessageKeys.BUPA_MISSING)); + + orders.filter(o -> o.getShippingAddressId() != null).forEach(order -> { + String addressId = order.getShippingAddressId(); + Result replica = db.run(Select.from(ADDRESSES).where(a -> a.businessPartner().eq(businessPartner).and(a.ID().eq(addressId)))); + // check if the address was not yet replicated + if(replica.rowCount() < 1) { + logger.info("Replicating Address '{}' from S/4 service", addressId); + Addresses remoteAddress = bupa.run(Select.from(ADDRESSES) + .where(a -> a.businessPartner().eq(businessPartner).and(a.ID().eq(addressId)))) + .single(Addresses.class); + + remoteAddress.setTombstone(false); + db.run(Insert.into(ADDRESSES).entry(remoteAddress)); + } + order.setShippingAddressBusinessPartner(businessPartner); + }); + } + + @On(service = ApiBusinessPartner_.CDS_NAME) + public void updateBusinessPartnerAddresses(BusinessPartnerChangedContext context) { + logger.info(">> received: " + context.getData()); + String businessPartner = context.getData().getBusinessPartner(); + + // fetch affected entries from local replicas + Result replicas = db.run(Select.from(ADDRESSES).where(a -> a.businessPartner().eq(businessPartner))); + if(replicas.rowCount() > 0) { + logger.info("Updating Addresses for BusinessPartner '{}'", businessPartner); + // fetch changed data from S/4 -> might be less than local due to deletes + Result remoteAddresses = bupa.run(Select.from(ADDRESSES).where(a -> a.businessPartner().eq(businessPartner))); + // update replicas or add tombstone if external address was deleted + replicas.streamOf(Addresses.class).forEach(rep -> { + Optional matching = remoteAddresses + .streamOf(Addresses.class) + .filter(ext -> ext.getId().equals(rep.getId())) + .findFirst(); + + if(!matching.isPresent()) { + rep.setTombstone(true); + } else { + matching.get().forEach(rep::put); + } + }); + // update local replicas with changes from S/4 + db.run(Upsert.into(ADDRESSES).entries(replicas)); + } + } + +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceAuditHandler.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceAuditHandler.java new file mode 100644 index 000000000..b8837772a --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceAuditHandler.java @@ -0,0 +1,144 @@ +package my.bookshop.handlers; + +import static cds.gen.adminservice.AdminService_.ORDERS; + +import java.util.Arrays; +import java.util.Optional; +import java.util.stream.Stream; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import com.sap.cds.ql.Select; +import com.sap.cds.ql.cqn.CqnDelete; +import com.sap.cds.services.EventContext; +import com.sap.cds.services.auditlog.Action; +import com.sap.cds.services.auditlog.AuditLogService; +import com.sap.cds.services.auditlog.ChangedAttribute; +import com.sap.cds.services.auditlog.ConfigChange; +import com.sap.cds.services.auditlog.DataObject; +import com.sap.cds.services.auditlog.KeyValuePair; +import com.sap.cds.services.cds.CdsDeleteEventContext; +import com.sap.cds.services.cds.CqnService; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.Before; +import com.sap.cds.services.handler.annotations.ServiceName; +import com.sap.cds.services.persistence.PersistenceService; + +import cds.gen.adminservice.AdminService_; +import cds.gen.adminservice.Orders; +import cds.gen.adminservice.Orders_; + +/** + * A custom handler that creates AuditLog messages. + */ +@Component +@ServiceName(AdminService_.CDS_NAME) +class AdminServiceAuditHandler implements EventHandler { + + private final PersistenceService db; + + private final AuditLogService auditLog; + + AdminServiceAuditHandler(PersistenceService db, AuditLogService auditLog) { + this.db = db; + this.auditLog = auditLog; + } + + @Before(event = { CqnService.EVENT_CREATE }) + public void beforeCreateOrder(Stream orders) { + orders.forEach(order -> { + ConfigChange cfgChange = createConfigChange(order, null); + this.auditLog.logConfigChange(Action.CREATE, cfgChange); + }); + } + + @Before(event = { CqnService.EVENT_UPDATE, CqnService.EVENT_UPSERT }) + public void beforeUpdateOrUpsertOrder(EventContext context, Stream orders) { + orders.forEach(order -> { + ConfigChange cfgChange = null; + Action action = null; + Optional oldOrders = readOldOrders(order.getId()); + if (oldOrders.isPresent()) { + if (!StringUtils.equals(order.getCurrencyCode(), oldOrders.get().getCurrencyCode())) { + cfgChange = createConfigChange(order, oldOrders.get()); + action = Action.UPDATE; + } + } else { + cfgChange = createConfigChange(order, null); + action = Action.CREATE; + } + if (cfgChange != null && action != null) { + auditCfgChange(action, cfgChange, context); + } + }); + } + + @Before(event = { CqnService.EVENT_DELETE }, entity = { Orders_.CDS_NAME }) + public void beforeDelete(CdsDeleteEventContext context) { + // prepare a select statement to read old currency code + Select ordersSelect = toSelect(context.getCqn()); + + // read old order number from DB + this.db.run(ordersSelect).first(Orders.class).ifPresent(oldOrders -> { + ConfigChange cfgChange = createConfigChange(null, oldOrders); + auditCfgChange(Action.DELETE, cfgChange, context); + }); + } + + private void auditCfgChange(final Action action, final ConfigChange cfgChange, EventContext context) { + // create new request context and send audit log message into provider tenant + context.getCdsRuntime().requestContext().systemUserProvider().run(ctx -> { + this.auditLog.logConfigChange(action, cfgChange); + }); + } + + private Optional readOldOrders(String ordersId) { + // prepare a select statement to read old order number + Select ordersSelect = Select.from(ORDERS).columns(Orders_::OrderNo) + .where(o -> o.ID().eq(ordersId).and(o.IsActiveEntity().eq(true))); + + // read old orders from DB + return this.db.run(ordersSelect).first(Orders.class); + } + + private static ConfigChange createConfigChange(Orders orders, Orders oldOrders) { + ChangedAttribute currencyCodeAttr = createChangedAttribute(orders != null ? orders.getCurrencyCode() : null, + oldOrders != null ? oldOrders.getCurrencyCode() : null); + + ConfigChange cfgChange = ConfigChange.create(); + cfgChange.setDataObject(createDataObject(orders != null ? orders : oldOrders)); + cfgChange.setAttributes(Arrays.asList(currencyCodeAttr)); + return cfgChange; + } + + private static DataObject createDataObject(Orders order) { + KeyValuePair id = createId(order); + + DataObject dataObject = DataObject.create(); + dataObject.setType(Orders_.CDS_NAME); + dataObject.setId(Arrays.asList(id)); + return dataObject; + } + + private static ChangedAttribute createChangedAttribute(String newValue, String oldValue) { + ChangedAttribute attribute = ChangedAttribute.create(); + attribute.setName(Orders.CURRENCY_CODE); + attribute.setOldValue(oldValue); + attribute.setNewValue(newValue); + return attribute; + } + + private static KeyValuePair createId(Orders order) { + KeyValuePair id = KeyValuePair.create(); + id.setKeyName(Orders.ID); + id.setValue(order.getId()); + return id; + } + + private static Select toSelect(CqnDelete delete) { + Select select = Select.from(delete.ref()); + delete.where().ifPresent(select::where); + return select; + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceHandler.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceHandler.java new file mode 100644 index 000000000..184a02950 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceHandler.java @@ -0,0 +1,456 @@ +package my.bookshop.handlers; + +import static cds.gen.adminservice.AdminService_.ORDERS; +import static cds.gen.adminservice.AdminService_.ORDER_ITEMS; +import static cds.gen.my.bookshop.Bookshop_.BOOKS; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import org.springframework.stereotype.Component; + +import com.sap.cds.Result; +import com.sap.cds.ql.Select; +import com.sap.cds.ql.Update; +import com.sap.cds.ql.Upsert; +import com.sap.cds.ql.cqn.CqnAnalyzer; +import com.sap.cds.reflect.CdsModel; +import com.sap.cds.services.ErrorStatuses; +import com.sap.cds.services.EventContext; +import com.sap.cds.services.ServiceException; +import com.sap.cds.services.cds.CdsUpdateEventContext; +import com.sap.cds.services.cds.CqnService; +import com.sap.cds.services.draft.DraftCancelEventContext; +import com.sap.cds.services.draft.DraftPatchEventContext; +import com.sap.cds.services.draft.DraftService; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.Before; +import com.sap.cds.services.handler.annotations.On; +import com.sap.cds.services.handler.annotations.ServiceName; +import com.sap.cds.services.messages.Messages; +import com.sap.cds.services.persistence.PersistenceService; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import cds.gen.adminservice.BooksAddToOrderContext; +import cds.gen.adminservice.AdminService; +import cds.gen.adminservice.AdminService_; +import cds.gen.adminservice.Books; +import cds.gen.adminservice.Books_; +import cds.gen.adminservice.OrderItems; +import cds.gen.adminservice.OrderItems_; +import cds.gen.adminservice.Orders; +import cds.gen.adminservice.Upload; +import cds.gen.adminservice.Upload_; +import cds.gen.my.bookshop.Bookshop_; +import my.bookshop.MessageKeys; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.Map; + +import com.sap.cds.ql.Insert; +import com.sap.cds.ql.cqn.CqnComparisonPredicate; +import com.sap.cds.ql.cqn.CqnConnectivePredicate; +import com.sap.cds.ql.cqn.CqnElementRef; +import com.sap.cds.ql.cqn.CqnLiteral; +import com.sap.cds.ql.cqn.CqnPredicate; +import com.sap.cds.ql.cqn.CqnReference; +import com.sap.cds.ql.cqn.CqnSelect; +import com.sap.cds.ql.cqn.CqnStructuredTypeRef; + +/** + * Custom business logic for the "Admin Service" (see admin-service.cds) + * + * Handles creating and editing orders. + */ +@Component +@ServiceName(AdminService_.CDS_NAME) +class AdminServiceHandler implements EventHandler { + + private static final Logger logger = LoggerFactory.getLogger(AdminServiceHandler.class); + + private final AdminService.Draft adminService; + + private final PersistenceService db; + + private final Messages messages; + + private final CqnAnalyzer analyzer; + + AdminServiceHandler(AdminService.Draft adminService, PersistenceService db, Messages messages, CdsModel model) { + this.adminService = adminService; + this.db = db; + this.messages = messages; + + // model is a tenant-dependant model proxy + this.analyzer = CqnAnalyzer.create(model); + } + + /** + * Validate correctness of an order before finishing the order proces: + * 1. Check Order quantity for each Item and return a message if quantity is empty or <= 0 + * 2. Check Order quantity for each Item is available, return message if the stock is too low + * + * @param orders + */ + @Before(event = { CqnService.EVENT_CREATE, CqnService.EVENT_UPSERT, CqnService.EVENT_UPDATE }) + public void beforeCreateOrder(Stream orders, EventContext context) { + orders.forEach(order -> { + // reset total + order.setTotal(BigDecimal.valueOf(0)); + if(order.getItems() != null) { + order.getItems().forEach(orderItem -> { + // validation of the Order creation request + Integer quantity = orderItem.getQuantity(); + if (quantity == null || quantity <= 0) { + // errors with localized messages from property files + // exceptions abort the request and set an error http status code + // messages in contrast allow to collect multiple errors + messages.error(MessageKeys.QUANTITY_REQUIRE_MINIMUM) + .target("in", ORDERS, o -> o.Items(i -> i.ID().eq(orderItem.getId()).and(i.IsActiveEntity().eq(orderItem.getIsActiveEntity()))).quantity()); + } + + String bookId = orderItem.getBookId(); + + if(quantity == null || quantity <= 0 || bookId == null) { + return; // follow up validations rely on these + } + + // calculate the actual quantity difference + // FIXME this should handle book changes, currently only quantity changes are handled + int diffQuantity = quantity - db.run(Select.from(Bookshop_.ORDER_ITEMS).columns(i -> i.quantity()).byId(orderItem.getId())) + .first(OrderItems.class).map(i -> i.getQuantity()).orElse(0); + + // check if enough books are available + Result result = db.run(Select.from(BOOKS).columns(b -> b.ID(), b -> b.stock(), b -> b.price()).byId(bookId)); + result.first(Books.class).ifPresent(book -> { + if (book.getStock() < diffQuantity) { + // Tip: you can have localized messages and use parameters in your messages + messages.error(MessageKeys.BOOK_REQUIRE_STOCK, book.getStock()) + .target("in", ORDERS, o -> o.Items(i -> i.ID().eq(orderItem.getId()).and(i.IsActiveEntity().eq(orderItem.getIsActiveEntity()))).quantity()); + return; // no need to update follow-up values with invalid quantity / stock + } + + // update the book with the new stock + book.setStock(book.getStock() - diffQuantity); + db.run(Update.entity(BOOKS).data(book)); + + // update the amount + BigDecimal updatedAmount = book.getPrice().multiply(BigDecimal.valueOf(quantity)); + orderItem.setAmount(updatedAmount); + + // update the total + order.setTotal(order.getTotal().add(updatedAmount)); + }); + }); + } + }); + } + + /** + * Calculate the total order value preview when editing an order item + * + * @param context + * @param orderItem + */ + @Before(event = DraftService.EVENT_DRAFT_PATCH) + public void patchOrderItems(DraftPatchEventContext context, OrderItems orderItem) { + // check if quantity or book was updated + Integer quantity = orderItem.getQuantity(); + String bookId = orderItem.getBookId(); + String orderItemId = orderItem.getId(); + BigDecimal amount = calculateAmountInDraft(orderItemId, quantity, bookId, true); + if (amount != null) { + orderItem.setAmount(amount); + } + } + + /** + * Calculate the total order value preview when deleting an order item from the order + * + * @param context + */ + @Before(event = DraftService.EVENT_DRAFT_CANCEL, entity = OrderItems_.CDS_NAME) + public void cancelOrderItems(DraftCancelEventContext context) { + String orderItemId = (String) analyzer.analyze(context.getCqn()).targetKeys().get(OrderItems.ID); + if(orderItemId != null) { + calculateAmountInDraft(orderItemId, 0, null, false); + } + } + + private BigDecimal calculateAmountInDraft(String orderItemId, Integer newQuantity, String newBookId, boolean includeWarnings) { + Integer quantity = newQuantity; + String bookId = newBookId; + if (quantity == null && bookId == null) { + return null; // nothing changed + } + + // get the order item that was updated (to get access to the book price, quantity and order total) + Result result = adminService.run(Select.from(ORDER_ITEMS) + .columns(o -> o.quantity(), o -> o.amount(), + o -> o.book().expand(b -> b.ID(), b -> b.price()), + o -> o.parent().expand(p -> p.ID(), p -> p.total())) + .where(o -> o.ID().eq(orderItemId).and(o.IsActiveEntity().eq(false)))); + OrderItems itemToPatch = result.first(OrderItems.class).orElseThrow(notFound(MessageKeys.ORDERITEM_MISSING)); + BigDecimal bookPrice = null; + + // fallback to existing values + if(quantity == null) { + quantity = itemToPatch.getQuantity(); + } + + if(bookId == null && itemToPatch.getBook() != null) { + bookId = itemToPatch.getBook().getId(); + bookPrice = itemToPatch.getBook().getPrice(); + } + + if(quantity == null || bookId == null) { + return null; // not enough data available + } + + // only warn about invalid values as we are in draft mode + if(includeWarnings && quantity <= 0) { + // Tip: add additional messages with localized messages from property files + // these messages are transported in sap-messages and do not abort the request + messages.warn(MessageKeys.QUANTITY_REQUIRE_MINIMUM); + } + + // get the price of the updated book ID + if(bookPrice == null) { + result = db.run(Select.from(BOOKS).byId(bookId).columns(b -> b.price())); + Books book = result.first(Books.class).orElseThrow(notFound(MessageKeys.BOOK_MISSING)); + bookPrice = book.getPrice(); + } + + // update the amount of the order item + BigDecimal updatedAmount = bookPrice.multiply(BigDecimal.valueOf(quantity)); + + // update the order's total + BigDecimal previousAmount = defaultZero(itemToPatch.getAmount()); + BigDecimal currentTotal = defaultZero(itemToPatch.getParent().getTotal()); + BigDecimal newTotal = currentTotal.subtract(previousAmount).add(updatedAmount); + adminService.patchDraft(Update.entity(ORDERS) + .where(o -> o.ID().eq(itemToPatch.getParent().getId()).and(o.IsActiveEntity().eq(false))) + .data(Orders.TOTAL, newTotal)); + + return updatedAmount; + } + + /** + * Adds a book to an order + * @param context + */ + @On(entity = Books_.CDS_NAME) + public void addBookToOrder(BooksAddToOrderContext context) { + String orderId = context.getOrderId(); + List orders = adminService.run(Select.from(ORDERS).columns(o -> o._all(), o -> o.Items().expand()).where(o -> o.ID().eq(orderId))).listOf(Orders.class); + Orders order = orders.stream().filter(p -> p.getIsActiveEntity()).findFirst().orElse(null); + + // check that the order with given ID exists and is not in draft-mode + if((orders.size() > 0 && order == null) || orders.size() > 1) { + throw new ServiceException(ErrorStatuses.CONFLICT, MessageKeys.ORDER_INDRAFT); + } else if (orders.size() <= 0) { + throw new ServiceException(ErrorStatuses.NOT_FOUND, MessageKeys.ORDER_MISSING); + } + + if(order.getItems() == null) { + order.setItems(new ArrayList<>()); + } + + // get ID of the book on which the action was called (bound action) + String bookId = (String) analyzer.analyze(context.getCqn()).targetKeys().get(Books.ID); + + // create order item + OrderItems newItem = OrderItems.create(); + newItem.setId(UUID.randomUUID().toString()); + newItem.setBookId(bookId); + newItem.setQuantity(context.getQuantity()); + order.getItems().add(newItem); + + Orders updatedOrder = adminService.run(Update.entity(ORDERS).data(order)).single(Orders.class); + messages.success(MessageKeys.BOOK_ADDED_ORDER); + context.setResult(updatedOrder); + } + + /** + * @return the static CSV singleton upload entity + */ + @On(entity = Upload_.CDS_NAME, event = CqnService.EVENT_READ) + public Upload getUploadSingleton() { + return Upload.create(); + } + + /** + * Handles CSV uploads with book data + * @param context + * @param csv + */ + @On + public void addBooksViaCsv(CdsUpdateEventContext context, Upload upload) { + InputStream is = upload.getCsv(); + if (is != null) { + try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) { + br.lines().skip(1).forEach((line) -> { + String[] p = line.split(";"); + Books book = Books.create(); + book.setId(p[0]); + book.setTitle(p[1]); + book.setDescr(p[2]); + book.setAuthorId(p[3]); + book.setStock(Integer.valueOf(p[4]).intValue()); + book.setPrice(BigDecimal.valueOf(Double.valueOf(p[5]))); + book.setCurrencyCode(p[6]); + book.setGenreId(Integer.valueOf(p[7])); + + // separate transaction per line + context.getCdsRuntime().changeSetContext().run(ctx -> { + db.run(Upsert.into(BOOKS).entry(book)); + }); + }); + } catch (IOException e) { + throw new ServiceException(ErrorStatuses.SERVER_ERROR, MessageKeys.BOOK_IMPORT_FAILED, e); + } catch (IndexOutOfBoundsException e) { + throw new ServiceException(ErrorStatuses.SERVER_ERROR, MessageKeys.BOOK_IMPORT_INVALID_CSV, e); + } + } + context.setResult(Arrays.asList(upload)); + } + + private Supplier notFound(String message) { + return () -> new ServiceException(ErrorStatuses.NOT_FOUND, message); + } + + private BigDecimal defaultZero(BigDecimal decimal) { + return decimal == null ? BigDecimal.valueOf(0) : decimal; + } + + /** + * Creates an attachment directly in the active entity state (bypassing draft flow). + * Triggered by the "Create Attachment" button visible only in active entity state. + */ + @On(event = "createAttachmentInActive") + public void createAttachmentInActive(EventContext context) { + String targetEntity = context.getTarget().getQualifiedName(); + logger.info("=== createAttachmentInActive triggered for entity: {} ===", targetEntity); + + // Guard: Skip framework-triggered invocations during edit+save. + // User clicks send "in" as null/empty (RequiresSelection: false). + Object inParam = context.get("in"); + if (inParam instanceof java.util.List && !((java.util.List) inParam).isEmpty()) { + logger.info("Skipping createAttachmentInActive — framework save, not user click"); + context.setCompleted(); + return; + } + + try { + CqnSelect cqn = (CqnSelect) context.get("cqn"); + Map rootKeys = analyzer.analyze(cqn).rootKeys(); + logger.info("Root keys: {}", rootKeys); + + String parentId = extractParentId(cqn, rootKeys); + + if (parentId == null || parentId.isEmpty()) { + logger.error("Could not extract parent ID from CQN. Root keys: {}", rootKeys); + throw new ServiceException(ErrorStatuses.BAD_REQUEST, "Parent entity ID is required to create attachment."); + } + + logger.info("Creating attachment for parent ID: {} in facet: {}", parentId, targetEntity); + + String attachmentId = UUID.randomUUID().toString(); + String timestamp = DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss-SSS") + .withZone(ZoneId.systemDefault()) + .format(Instant.now()); + String fileName = "attachment-" + timestamp + ".txt"; + + String sampleContent = "Sample Attachment\nCreated: " + Instant.now() + + "\nParent ID: " + parentId + + "\nFacet: " + targetEntity; + + InputStream contentStream = new ByteArrayInputStream( + sampleContent.getBytes(StandardCharsets.UTF_8)); + + Map attachmentData = new HashMap<>(); + attachmentData.put("ID", attachmentId); + attachmentData.put("up__ID", parentId); + attachmentData.put("fileName", fileName); + attachmentData.put("mimeType", "text/plain"); + attachmentData.put("note", "Created in active entity"); + attachmentData.put("content", contentStream); + + adminService.run(Insert.into(targetEntity).entry(attachmentData)); + logger.info("Attachment created with ID: {}", attachmentId); + + context.setCompleted(); + + } catch (ServiceException e) { + throw e; + } catch (Exception e) { + logger.error("Failed to create attachment: {}", e.getMessage(), e); + context.setCompleted(); + throw new ServiceException(ErrorStatuses.SERVER_ERROR, "Failed to create attachment: " + e.getMessage(), e); + } + } + + private String extractParentId(CqnSelect cqn, Map rootKeys) { + // Case 1: Direct entity — rootKeys has up__ID + Object upId = rootKeys.get("up__ID"); + if (upId != null) { + return upId.toString(); + } + + // Case 2: Nested composition path — traverse CQN segments + try { + if (cqn.from().isRef()) { + CqnStructuredTypeRef ref = cqn.from().asRef(); + java.util.List segments = ref.segments(); + if (segments.size() >= 2) { + CqnReference.Segment parentSegment = segments.get(segments.size() - 2); + if (parentSegment.filter().isPresent()) { + String parentId = extractIdFromPredicate(parentSegment.filter().get()); + if (parentId != null) return parentId; + } + } + } + } catch (Exception e) { + logger.warn("Could not extract parent ID from CQN path: {}", e.getMessage()); + } + + // Fallback + Object id = rootKeys.get("ID"); + return id != null ? id.toString() : null; + } + + private String extractIdFromPredicate(CqnPredicate predicate) { + if (predicate instanceof CqnComparisonPredicate) { + CqnComparisonPredicate comp = (CqnComparisonPredicate) predicate; + if (comp.left() instanceof CqnElementRef && comp.right() instanceof CqnLiteral) { + String fieldName = ((CqnElementRef) comp.left()).lastSegment(); + if ("ID".equals(fieldName)) { + return ((CqnLiteral) comp.right()).value().toString(); + } + } + } else if (predicate instanceof CqnConnectivePredicate) { + for (CqnPredicate child : ((CqnConnectivePredicate) predicate).predicates()) { + String id = extractIdFromPredicate(child); + if (id != null) return id; + } + } + return null; + } + +} \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/BookRatingInitialization.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/BookRatingInitialization.java new file mode 100644 index 000000000..6e482dfd2 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/BookRatingInitialization.java @@ -0,0 +1,31 @@ +package my.bookshop.handlers; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import com.sap.cds.services.application.ApplicationLifecycleService; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.After; +import com.sap.cds.services.handler.annotations.ServiceName; + +import my.bookshop.RatingCalculator; + +/** + * Initializes the book ratings based on their review ratings. + */ +@Component +@Profile("default") +@ServiceName(ApplicationLifecycleService.DEFAULT_NAME) +public class BookRatingInitialization implements EventHandler { + + private RatingCalculator ratingCalculator; + + BookRatingInitialization(RatingCalculator ratingCalculator) { + this.ratingCalculator = ratingCalculator; + } + + @After(event = ApplicationLifecycleService.EVENT_APPLICATION_PREPARED) + public void initBookRatings() { + this.ratingCalculator.initBookRatings(); + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/CatalogServiceHandler.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/CatalogServiceHandler.java new file mode 100644 index 000000000..1eae1a8cc --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/CatalogServiceHandler.java @@ -0,0 +1,194 @@ +package my.bookshop.handlers; + +import static cds.gen.catalogservice.CatalogService_.BOOKS; +import static cds.gen.catalogservice.CatalogService_.REVIEWS; + +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.springframework.stereotype.Component; + +import com.sap.cds.Result; +import com.sap.cds.Struct; +import com.sap.cds.ql.Insert; +import com.sap.cds.ql.Select; +import com.sap.cds.ql.Update; +import com.sap.cds.ql.cqn.CqnAnalyzer; +import com.sap.cds.ql.cqn.CqnSelect; +import com.sap.cds.reflect.CdsModel; +import com.sap.cds.services.ErrorStatuses; +import com.sap.cds.services.ServiceException; +import com.sap.cds.services.cds.CdsReadEventContext; +import com.sap.cds.services.cds.CqnService; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.After; +import com.sap.cds.services.handler.annotations.Before; +import com.sap.cds.services.handler.annotations.On; +import com.sap.cds.services.handler.annotations.ServiceName; +import com.sap.cds.services.messages.Messages; +import com.sap.cds.services.persistence.PersistenceService; +import com.sap.cds.services.request.FeatureTogglesInfo; + +import cds.gen.catalogservice.BooksAddReviewContext; +import cds.gen.catalogservice.Books; +import cds.gen.catalogservice.Books_; +import cds.gen.catalogservice.CatalogService_; +import cds.gen.catalogservice.Reviews; +import cds.gen.catalogservice.SubmitOrderContext; +import cds.gen.reviewservice.ReviewService; +import cds.gen.reviewservice.ReviewService_; +import my.bookshop.MessageKeys; +import my.bookshop.RatingCalculator; + +/** + * Custom business logic for the "Catalog Service" (see cat-service.cds) + * + * Handles Reading of Books + * + * Adds Discount Message to the Book Title if too much stock is available + * + * Provides adding book reviews + */ +@Component +@ServiceName(CatalogService_.CDS_NAME) +class CatalogServiceHandler implements EventHandler { + + private final PersistenceService db; + private final ReviewService reviewService; + + private final Messages messages; + private final FeatureTogglesInfo featureToggles; + private final RatingCalculator ratingCalculator; + private final CqnAnalyzer analyzer; + + CatalogServiceHandler(PersistenceService db, ReviewService reviewService, Messages messages, + FeatureTogglesInfo featureToggles, RatingCalculator ratingCalculator, CdsModel model) { + this.db = db; + this.reviewService = reviewService; + this.messages = messages; + this.featureToggles = featureToggles; + this.ratingCalculator = ratingCalculator; + this.analyzer = CqnAnalyzer.create(model); + } + + /** + * Invokes some validations before creating a review. + * + * @param context {@link ReviewContext} + */ + @Before(entity = Books_.CDS_NAME) + public void beforeAddReview(BooksAddReviewContext context) { + String user = context.getUserInfo().getName(); + String bookId = (String) analyzer.analyze(context.getCqn()).targetKeys().get(Books.ID); + + Result result = db.run(Select.from(REVIEWS) + .where(review -> review.book_ID().eq(bookId).and(review.createdBy().eq(user)))); + + if (result.first().isPresent()) { + throw new ServiceException(ErrorStatuses.METHOD_NOT_ALLOWED, MessageKeys.REVIEW_ADD_FORBIDDEN) + .messageTarget(REVIEWS, r -> r.createdBy()); + } + } + + /** + * Handles the review creation from the given context. + * + * @param context {@link ReviewContext} + */ + @On(entity = Books_.CDS_NAME) + public void onAddReview(BooksAddReviewContext context) { + String bookId = (String) analyzer.analyze(context.getCqn()).targetKeys().get(Books.ID); + cds.gen.reviewservice.Reviews review = cds.gen.reviewservice.Reviews.create(); + review.setBookId(bookId); + review.setRating(context.getRating()); + review.setTitle(context.getTitle()); + review.setText(context.getText()); + + Result res = reviewService.run(Insert.into(ReviewService_.REVIEWS).entry(review)); + cds.gen.reviewservice.Reviews inserted = res.single(cds.gen.reviewservice.Reviews.class); + + messages.success(MessageKeys.REVIEW_ADDED); + context.setResult(Struct.access(inserted).as(Reviews.class)); + } + + /** + * Recalculates and sets the book rating after a new review for the given book. + * + * @param context {@link ReviewContext} + */ + @After(entity = Books_.CDS_NAME) + public void afterAddReview(BooksAddReviewContext context) { + ratingCalculator.setBookRating(context.getResult().getBookId()); + } + + @After(event = CqnService.EVENT_READ) + public void discountBooks(Stream books) { + books.filter(b -> b.getTitle() != null).forEach(b -> { + loadStockIfNotSet(b); + discountBooksWithMoreThan111Stock(b, featureToggles.isEnabled("discount")); + }); + } + + @After + public void setIsReviewable(CdsReadEventContext context, List books) { + String user = context.getUserInfo().getName(); + List bookIds = books.stream().filter(b -> b.getId() != null).map(b -> b.getId()) + .collect(Collectors.toList()); + + if (bookIds.isEmpty()) { + return; + } + + CqnSelect query = Select.from(BOOKS, b -> b.filter(b.ID().in(bookIds)).reviews()) + .where(r -> r.createdBy().eq(user)); + + Set reviewedBooks = db.run(query).streamOf(Reviews.class).map(Reviews::getBookId) + .collect(Collectors.toSet()); + + for (Books book : books) { + if (reviewedBooks.contains(book.getId())) { + book.setIsReviewable(false); + } + } + } + + @On + public void onSubmitOrder(SubmitOrderContext context) { + Integer quantity = context.getQuantity(); + String bookId = context.getBook(); + + Optional book = db.run(Select.from(BOOKS).columns(Books_::stock).byId(bookId)).first(Books.class); + + book.orElseThrow(() -> new ServiceException(ErrorStatuses.NOT_FOUND, MessageKeys.BOOK_MISSING) + .messageTarget(BOOKS, b -> b.ID())); + + int stock = book.map(Books::getStock).get(); + + if (stock >= quantity) { + db.run(Update.entity(BOOKS).byId(bookId).data(Books.STOCK, stock -= quantity)); + + SubmitOrderContext.ReturnType result = SubmitOrderContext.ReturnType.create(); + result.setStock(stock); + + context.setResult(result); + } else { + throw new ServiceException(ErrorStatuses.CONFLICT, MessageKeys.ORDER_EXCEEDS_STOCK, quantity); + } + } + + private void discountBooksWithMoreThan111Stock(Books b, boolean premium) { + if (b.getStock() != null && b.getStock() > 111) { + b.setTitle(String.format("%s -- %s%% discount", b.getTitle(), premium ? 14 : 11)); + } + } + + private void loadStockIfNotSet(Books b) { + if (b.getId() != null && b.getStock() == null) { + b.setStock(db.run(Select.from(BOOKS).byId(b.getId()).columns(Books_::stock)).single(Books.class).getStock()); + } + } + +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/DependencyExit.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/DependencyExit.java new file mode 100644 index 000000000..2bdd059a5 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/DependencyExit.java @@ -0,0 +1,104 @@ +package my.bookshop.handlers; + +import java.io.UnsupportedEncodingException; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.sap.cds.Struct; +import com.sap.cds.sdm.model.Repository; +import com.sap.cds.sdm.model.RepositoryParams; +import com.sap.cds.sdm.service.SDMAdminService; +import com.sap.cds.sdm.service.SDMAdminServiceImpl; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.After; +import com.sap.cds.services.handler.annotations.On; +import com.sap.cds.services.handler.annotations.ServiceName; +import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; +import com.sap.cds.services.mt.*; +import com.sap.cloud.environment.servicebinding.api.ServiceBinding; + +import java.util.*; +@Component +@ServiceName(DeploymentService.DEFAULT_NAME) +class DependencyExit implements EventHandler { + + @On(event = DeploymentService.EVENT_DEPENDENCIES) + public void onGetDependencies(DependenciesEventContext context) { + + List dependencies = new ArrayList<>(); + Map uaa = (Map) getSDMCredentials().get("uaa"); + dependencies.add(SaasRegistryDependency.create(uaa.get("xsappname").toString())); + context.setResult(dependencies); + } + private Map getSDMCredentials() { + List allServiceBindings = + DefaultServiceBindingAccessor.getInstance().getServiceBindings(); +// filter for a specific binding +ServiceBinding sdmBinding = + allServiceBindings.stream() + .filter(binding -> "sdm".equalsIgnoreCase(binding.getServiceName().orElse(null))) + .findFirst() + .get(); +return sdmBinding.getCredentials(); + + } + + @After(event = DeploymentService.EVENT_SUBSCRIBE) + public void onSubscribe(SubscribeEventContext context) throws JsonProcessingException,UnsupportedEncodingException { + //use httpclient and onboard a repository + System.out.println("After subscribing to my CAP application"); + final SaasRegistrySubscriptionOptions options = Struct + .access(context.getOptions()) + .as(SaasRegistrySubscriptionOptions.class); + + // Access the specific property + final String subdomain = options.getSubscribedSubdomain(); +SDMAdminService sdmAdminService = new SDMAdminServiceImpl(); + +Repository repository = new Repository(); +repository.setDescription("Onboarding Repo Demo"); +repository.setDisplayName(" Test Onboarding repo"); +repository.setSubdomain(subdomain); +repository.setHashAlgorithms("SHA-256"); +repository.setIsEncryptionEnabled(false); +repository.setIsVirusScanEnabled(false); +repository.setExternalId("MULTITENANT-TEST-REPO"); +List repositoryParams = new ArrayList<>(); +RepositoryParams repositoryParam = new RepositoryParams(); + repositoryParam.setParamName("fileExtensions"); + JsonObject fileExtensionsValue = new JsonObject(); + fileExtensionsValue.addProperty("type", "block"); + fileExtensionsValue.add( + "list", new Gson().toJsonTree(new String[] {"docx","pptx","rtf"})); + + // Convert the nested JSON object to a JSON string + String jsonParamValue = fileExtensionsValue.toString(); + repositoryParam.setParamValue(jsonParamValue); + repositoryParams.add(repositoryParam); + repository.setRepositoryParams(repositoryParams); + repository.setIsVersionEnabled(false); + System.out.println("Repo Param "+repositoryParams); + System.out.println("Repo "+repository); +String response = sdmAdminService.onboardRepository(repository); +System.out.println("Onboard response "+response); + } + + @After(event = DeploymentService.EVENT_UNSUBSCRIBE) + public void afterUnsubscribe(UnsubscribeEventContext context) { + //delete onboarded repository + System.out.println("After unsubscribing to my CAP application"); + final SaasRegistrySubscriptionOptions options = Struct + .access(context.getOptions()) + .as(SaasRegistrySubscriptionOptions.class); + // Access the specific property + final String subdomain = options.getSubscribedSubdomain(); + System.out.println("subdomain "+subdomain); + + SDMAdminService sdmAdminService = new SDMAdminServiceImpl(); + String res = sdmAdminService.offboardRepository(subdomain); + System.out.println(res); + } + +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/NotesServiceHandler.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/NotesServiceHandler.java new file mode 100644 index 000000000..26d9a2e9d --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/NotesServiceHandler.java @@ -0,0 +1,208 @@ +package my.bookshop.handlers; + +import static cds.gen.notesservice.NotesService_.ADDRESSES; +import static cds.gen.notesservice.NotesService_.NOTES; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import com.sap.cds.Result; +import com.sap.cds.ql.CQL; +import com.sap.cds.ql.Predicate; +import com.sap.cds.ql.Select; +import com.sap.cds.ql.cqn.CqnAnalyzer; +import com.sap.cds.ql.cqn.CqnExpand; +import com.sap.cds.ql.cqn.CqnPredicate; +import com.sap.cds.ql.cqn.CqnReference.Segment; +import com.sap.cds.ql.cqn.CqnSelect; +import com.sap.cds.ql.cqn.CqnSelectListItem; +import com.sap.cds.ql.cqn.CqnStructuredTypeRef; +import com.sap.cds.ql.cqn.Modifier; +import com.sap.cds.reflect.CdsModel; +import com.sap.cds.services.cds.CdsReadEventContext; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.On; +import com.sap.cds.services.handler.annotations.ServiceName; + +import cds.gen.api_business_partner.ApiBusinessPartner; +import cds.gen.api_business_partner.ApiBusinessPartner_; +import cds.gen.notesservice.Addresses; +import cds.gen.notesservice.Addresses_; +import cds.gen.notesservice.Notes; +import cds.gen.notesservice.NotesService_; +import cds.gen.notesservice.Notes_; + +@Component +@ServiceName(NotesService_.CDS_NAME) +public class NotesServiceHandler implements EventHandler { + + private final ApiBusinessPartner bupa; + private final CqnAnalyzer analyzer; + + NotesServiceHandler(@Qualifier(ApiBusinessPartner_.CDS_NAME) ApiBusinessPartner bupa, CdsModel model) { + this.bupa = bupa; + this.analyzer = CqnAnalyzer.create(model); + } + + @On(entity = Addresses_.CDS_NAME) + Result readAddresses(CdsReadEventContext context) { + List segments = context.getCqn().ref().segments(); + // via note + if(segments.size() == 2 && segments.get(0).id().equals(Notes_.CDS_NAME)) { + Map noteKeys = analyzer.analyze(context.getCqn()).rootKeys(); + Notes note = context.getService().run(Select.from(NOTES).columns(n -> n.address_businessPartner(), n -> n.address_ID()).matching(noteKeys)).single(Notes.class); + CqnSelect addressOfNote = CQL.copy(context.getCqn(), new Modifier() { + + @Override + public CqnStructuredTypeRef ref(CqnStructuredTypeRef ref) { + return CQL.entity(Addresses_.CDS_NAME) + .filter(p -> p.get(Addresses.BUSINESS_PARTNER).eq(note.getAddressBusinessPartner()) + .and(p.get(Addresses.ID).eq(note.getAddressId()))) + .asRef(); + } + + }); + return context.getService().run(addressOfNote); + } + + // notes expanded? + AtomicReference notesExpandHolder = new AtomicReference<>(); + CqnSelect noNotesExpand = CQL.copy(context.getCqn(), new Modifier() { + + public List items(List items) { + notesExpandHolder.set(removeIfExpanded(items, Addresses.NOTES)); + return ensureSelected(items, Addresses.BUSINESS_PARTNER, Addresses.ID); + } + + }); + + // read addresses + Result addresses = bupa.run(noNotesExpand); + + // add expanded notes? + CqnExpand notesExpand = notesExpandHolder.get(); + if(notesExpand != null) { + Select notesSelect = Select.from(NOTES) + .columns(ensureSelected(notesExpand.items(), Notes.ADDRESS_BUSINESS_PARTNER, Notes.ADDRESS_ID)) + .orderBy(notesExpand.orderBy()) + .where(n -> CQL.or(addresses.streamOf(Addresses.class) + .map(address -> n.address_businessPartner().eq(address.getBusinessPartner()).and(n.address_ID().eq(address.getId()))) + .collect(Collectors.toList())) + .and(predicate(notesExpand.ref().rootSegment()))); + + Result notes = context.getService().run(notesSelect); + for(Addresses address : addresses.listOf(Addresses.class)) { + address.setNotes( + notes.streamOf(Notes.class) + .filter(n -> n.getAddressBusinessPartner().equals(address.getBusinessPartner()) + && n.getAddressId().equals(address.getId())) + .collect(Collectors.toList())); + } + } + + return addresses; + } + + @On(entity = Notes_.CDS_NAME) + void readNotes(CdsReadEventContext context) { + List segments = context.getCqn().ref().segments(); + // via addresses + if(segments.size() == 2 && segments.get(0).id().equals(Addresses_.CDS_NAME)) { + Map addressKeys = analyzer.analyze(context.getCqn()).rootKeys(); + CqnSelect notesOfAddress = CQL.copy(context.getCqn(), new Modifier() { + + @Override + public CqnStructuredTypeRef ref(CqnStructuredTypeRef ref) { + return CQL.entity(Notes_.CDS_NAME).filter(predicate(segments.get(1))).asRef(); + } + + @Override + public Predicate where(Predicate where) { + Predicate ofAddress = CQL.get(Notes.ADDRESS_BUSINESS_PARTNER).eq(addressKeys.get(Addresses.BUSINESS_PARTNER)) + .and(CQL.get(Notes.ADDRESS_ID).eq(addressKeys.get(Addresses.ID))); + if(where != null) { + ofAddress = ofAddress.and(where); + } + return ofAddress; + } + + }); + context.setResult(context.getService().run(notesOfAddress)); + return; + } + + // address expanded? + AtomicReference addressExpandHolder = new AtomicReference<>(); + CqnSelect noAddressExpand = CQL.copy(context.getCqn(), new Modifier() { + + public List items(List items) { + addressExpandHolder.set(removeIfExpanded(items, Notes.ADDRESS)); + return ensureSelected(items, Notes.ADDRESS_BUSINESS_PARTNER, Notes.ADDRESS_ID); + } + + }); + + CqnExpand addressExpand = addressExpandHolder.get(); + if(addressExpand != null) { + // read notes and join with addresses + Result notes = context.getService().run(noAddressExpand); + List notesWithAddresses = notes.streamOf(Notes.class).filter(n -> n.getAddressBusinessPartner() != null && n.getAddressId() != null).collect(Collectors.toList()); + if (notesWithAddresses.size() > 0) { + Select addressSelect = Select.from(ADDRESSES) + .columns(ensureSelected(addressExpand.items(), Addresses.BUSINESS_PARTNER, Addresses.ID)) + .orderBy(addressExpand.orderBy()) + .where(a -> CQL.or(notesWithAddresses.stream() + .map(n -> a.businessPartner().eq(n.getAddressBusinessPartner()).and(a.ID().eq(n.getAddressId()))) + .collect(Collectors.toList())) + .and(predicate(addressExpand.ref().rootSegment()))); + + Result addresses = context.getService().run(addressSelect); + for(Notes note : notes.listOf(Notes.class)) { + note.setAddress(addresses.streamOf(Addresses.class) + .filter(a -> a.getBusinessPartner().equals(note.getAddressBusinessPartner()) + && a.getId().equals(note.getAddressId())) + .findFirst().orElse(null)); + } + } + context.setResult(notes); + return; + } + } + + private CqnExpand removeIfExpanded(List items, String association) { + CqnExpand expanded = items.stream().filter(i -> i.isExpand()).map(i -> i.asExpand()) + .filter(i -> i.ref().firstSegment().equals(association)).findFirst().orElse(null); + if(expanded != null) { + items.remove(expanded); + } + return expanded; + } + + private List ensureSelected(List items, String... elements) { + if(items.stream().anyMatch(i -> i.isStar())) { + return items; + } + Set newElements = new HashSet<>(); + for(String element : elements) { + if(!items.stream().anyMatch(i -> i.isValue() && i.asValue().displayName().equals(element))) { + newElements.add(element); + } + } + List newItems = new ArrayList<>(items); + newElements.forEach(element -> newItems.add(CQL.get(element))); + return newItems; + } + + private CqnPredicate predicate(Segment segment) { + return segment.filter().orElse(CQL.constant(true).eq(true)); + } + +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/OnboardRepository.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/OnboardRepository.java new file mode 100644 index 000000000..3ce44b240 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/OnboardRepository.java @@ -0,0 +1,14 @@ +package my.bookshop.handlers; + +public class OnboardRepository { + private Repository repository; + + public Repository getRepository() { + return repository; + } + + public void setRepository(Repository repository) { + this.repository = repository; + } + +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/Repository.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/Repository.java new file mode 100644 index 000000000..0fa1c335b --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/Repository.java @@ -0,0 +1,36 @@ +package my.bookshop.handlers; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class Repository { + private String displayName; + private String externalId; + private String description; + private String repositoryId; +public String getDisplayName() { + return displayName; +} +public void setDisplayName(String displayName) { + this.displayName = displayName; +} +public String getExternalId() { + return externalId; +} +public void setExternalId(String externalId) { + this.externalId = externalId; +} +public String getDescription() { + return description; +} +public void setDescription(String description) { + this.description = description; +} +public String getRepositoryId() { + return repositoryId; +} +public void setRepositoryId(String repositoryId) { + this.repositoryId = repositoryId; +} + +} + diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/SubscriptionHandler.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/SubscriptionHandler.java new file mode 100644 index 000000000..8b70715fb --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/SubscriptionHandler.java @@ -0,0 +1,33 @@ +package my.bookshop.handlers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import com.sap.cds.services.auditlog.AuditLogService; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.After; +import com.sap.cds.services.handler.annotations.ServiceName; +import com.sap.cds.services.mt.DeploymentService; +import com.sap.cds.services.mt.SubscribeEventContext; + +/** + * Handler that implements subscription logic + */ +@Component +@Profile("cloud") +@ServiceName(DeploymentService.DEFAULT_NAME) +class SubscriptionHandler implements EventHandler { + + @Autowired + private AuditLogService auditLog; + + @After + public void afterSubscribe(SubscribeEventContext context) { + String msg = String.format("New tenant '%s' subscribed.", context.getTenant()); + + // send audit log security message to provider tenant as user's tenant is null + auditLog.logSecurityEvent("tenant subscribed", msg); + } + +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/external/ApiBusinessPartnerEventMockHandler.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/external/ApiBusinessPartnerEventMockHandler.java new file mode 100644 index 000000000..2a353754f --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/external/ApiBusinessPartnerEventMockHandler.java @@ -0,0 +1,50 @@ +package my.bookshop.handlers.external; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import com.sap.cds.ql.cqn.CqnAnalyzer; +import com.sap.cds.services.cds.ApplicationService; +import com.sap.cds.services.cds.CdsUpdateEventContext; +import com.sap.cds.services.cds.CqnService; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.After; +import com.sap.cds.services.handler.annotations.ServiceName; + +import cds.gen.api_business_partner.ABusinessPartnerAddress; +import cds.gen.api_business_partner.ABusinessPartnerAddress_; +import cds.gen.api_business_partner.ApiBusinessPartner_; +import cds.gen.api_business_partner.BusinessPartnerChanged; +import cds.gen.api_business_partner.BusinessPartnerChangedContext; + +/** + * This class mocks the event emitting of the S/4 API + */ +@Component +@Profile("!cloud") +@ServiceName(value = { ApiBusinessPartner_.CDS_NAME, "api-business-partner-mocked"}, type = ApplicationService.class) +public class ApiBusinessPartnerEventMockHandler implements EventHandler { + + private final static Logger logger = LoggerFactory.getLogger(ApiBusinessPartnerEventMockHandler.class); + + @After(event = CqnService.EVENT_UPDATE, entity = ABusinessPartnerAddress_.CDS_NAME) + public void businessPartnerChanged(CdsUpdateEventContext context) { + // Get BusinessPartner ID + CqnAnalyzer analyzer = CqnAnalyzer.create(context.getModel()); + String businessPartner = (String) analyzer.analyze(context.getCqn().ref()).targetKeys().get(ABusinessPartnerAddress.BUSINESS_PARTNER); + + // Construct S/4 HANA Payload + BusinessPartnerChanged payload = BusinessPartnerChanged.create(); + payload.setBusinessPartner(businessPartner); + + // Emit Changed Event + logger.info("<< emitting: " + payload); + BusinessPartnerChangedContext changed = BusinessPartnerChangedContext.create(); + changed.setData(payload); + context.getService().emit(changed); + } + + +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/health/AppActuator.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/health/AppActuator.java new file mode 100644 index 000000000..e661e1f4f --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/health/AppActuator.java @@ -0,0 +1,27 @@ +package my.bookshop.health; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; +import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.stereotype.Component; + + +/** + * Custom app actuator implementation. + */ +@Component +@ConditionalOnClass(Endpoint.class) +@Endpoint(id = "bookshop", enableByDefault = true) +public class AppActuator { + + @ReadOperation + public Map info() { + Map info = new LinkedHashMap<>(); + info.put("Version", "1.0.0"); + return info; + } + +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/health/CustomHealthIndicator.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/health/CustomHealthIndicator.java new file mode 100644 index 000000000..ba702f7f7 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/health/CustomHealthIndicator.java @@ -0,0 +1,28 @@ +package my.bookshop.health; + +import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.stereotype.Component; + +/** + * Custom health indicator implementation. + */ +@Component("myhealth") +@ConditionalOnEnabledHealthIndicator("myhealth") +public class CustomHealthIndicator implements HealthIndicator { + + @Override + public Health health() { + if (check() != 0) { + return Health.down().build(); + } + return Health.up().build(); + } + + private int check() { + // perform some health check + return 0; + } + +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/META-INF/native-image/resource-config.json b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/META-INF/native-image/resource-config.json new file mode 100644 index 000000000..5eb7cfcad --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/META-INF/native-image/resource-config.json @@ -0,0 +1,12 @@ +{ + "resources": { + "includes": [ + { + "pattern": "\\Qmessages.properties\\E" + }, + { + "pattern": "\\Qmessages_de.properties\\E" + } + ] + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/application.yaml b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/application.yaml new file mode 100644 index 000000000..b956b4b62 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/application.yaml @@ -0,0 +1,136 @@ +--- +logging: + level: + '[com.sap.cds.auditlog]': DEBUG +spring: + jmx: + enabled: true +cds: + odata-v4: + endpoint.path: "/api" + lazy-i18n.enabled: true + multi-tenancy: + compatibility.enabled: false + mtxs.enabled: true + security: + authentication.normalize-provider-tenant: true + mock.users: + admin: + password: admin + roles: + - admin + attributes: + businessPartner: + - "10401010" + user: + password: user +server.servlet.encoding: + charset: UTF-8 + force: true +management: + endpoint: + health: + show-components: always + show-details: always + endpoints: + web: + exposure: + include: "health" + health: + defaults.enabled: false + ping.enabled: true + db.enabled: true + myhealth.enabled: true + +--- +spring: + config.activate.on-profile: cloud + sql.init.schema-locations: "classpath:schema-nomocks.sql" +cds: + sql.hana: + optimizationMode: hex + search: + fuzzy: true + fuzzinessThreshold: 0.9 + messaging.services: + bupa-messaging: + kind: enterprise-messaging + format: cloudevents + subscribe-prefix: sap/S4HANAOD/java/ce/ + +--- +spring: + config.activate.on-profile: sandbox +cds: + remote.services: + '[API_BUSINESS_PARTNER]': + type: "odata-v2" + http: + headers: + APIKey: "" # Place API Key from SAP API Business Hub here or use environment variable CDS_REMOTE_SERVICES_API_BUSINESS_PARTNER_HTTP_HEADERS_APIKEY + destination: + properties: + url: "https://sandbox.api.sap.com/s4hanacloud/sap/opu/odata/sap" + +--- +spring: + config.activate.on-profile: destination +cds: + remote.services: + '[API_BUSINESS_PARTNER]': + type: "odata-v2" + http: + suffix: "/sap/opu/odata/sap" + destination: + name: "s4-destination" + +--- +spring: + config.activate.on-profile: mocked +cds: + messaging.services: + bupa-messaging: + kind: file-based-messaging + application.services: + api-business-partner-mocked: + model: API_BUSINESS_PARTNER + serve: + path: API_BUSINESS_PARTNER + remote.services: + '[API_BUSINESS_PARTNER]': + http: + suffix: "/api" + destination: + name: "myself" + +--- +spring: + config.activate.on-profile: ft +cds: + model.provider.url: http://localhost:4005 + security.mock.users: + admin: + features: + - isbn + - discount + user: + features: + - isbn + +--- +spring: + config.activate.on-profile: local-mtxs +cds: + multi-tenancy.sidecar.url: http://localhost:4005 + security.mock.users: + admin: + tenant: t1 + user: + tenant: t1 + +--- +spring: + config.activate.on-profile: default +cds: + data-source: + auto-config.enabled: false diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/logback-spring.xml b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/logback-spring.xml new file mode 100644 index 000000000..bef4441a1 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/logback-spring.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/messages.properties b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/messages.properties new file mode 100644 index 000000000..67a07e3fa --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/messages.properties @@ -0,0 +1,14 @@ +quantity.require.minimum = The specified quantity is smaller than 1 +book.require.stock = Not enough books on stock (only {0} left) +book.added.order = Book successfully added to order +book.missing = Book does not exist +orderitem.missing = OrderItem does not exist +order.missing = Order does not exist +order.indraft = Order is currently in draft mode +bupa.missing = No Business Parter for this user available +review.added = Review added +order.exceeds.stock = {0} exceeds stock for book +review.add.forbidden=User not allowed to add more than one review for a given book +book.import.failed = Import of books failed +book.import.invalid.csv = Invalid CSV structure found - Please check its content +SDM.Attachments.maxCountError = Maximum number of attachments reached in English diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/messages_de.properties b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/messages_de.properties new file mode 100644 index 000000000..f498bbe00 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/messages_de.properties @@ -0,0 +1,13 @@ +quantity.require.minimum = Die eingetragene Anzahl ist kleiner als 1 +book.require.stock = Nicht genügend Bücher auf Vorrat (nur {0} übrig) +book.added.order = Das Buch wurde der Bestellung erfolgreich hinzugefügt +book.missing = Das Buch existiert nicht +orderitem.missing = Der Bestellungseintrag existiert nicht +order.missing = Die Bestellung existiert nicht +order.indraft = Die Bestellung ist bereits in Bearbeitung +bupa.missing = Kein Business Parter für diesen User verfügbar +review.added = Bewertung hinzugefügt +order.exceeds.stock = {0} ist mehr als für das Buch auf Vorrat übrig ist +review.add.forbidden = Es ist nicht mehr als eine Bewertung pro Buch erlaubt +book.import.failed = Bücher Import fehlgeschlagen +book.import.invalid.csv = Die CSV Datei enthält eine ungültige Struktur - Bitte überprüfen Sie den Inhalt \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/schema-nomocks.sql b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/schema-nomocks.sql new file mode 100644 index 000000000..dc0c09419 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/schema-nomocks.sql @@ -0,0 +1,1270 @@ + +DROP VIEW IF EXISTS localized_AdminService_Orders_changes; +DROP VIEW IF EXISTS localized_AdminService_Orders; +DROP VIEW IF EXISTS localized_ReviewService_Books_attachments; +DROP VIEW IF EXISTS localized_ReviewService_Authors; +DROP VIEW IF EXISTS localized_ReviewService_Reviews; +DROP VIEW IF EXISTS localized_CatalogService_Books_attachments; +DROP VIEW IF EXISTS localized_CatalogService_Reviews; +DROP VIEW IF EXISTS localized_CatalogService_Authors; +DROP VIEW IF EXISTS localized_AdminService_OrderItems; +DROP VIEW IF EXISTS localized_AdminService_Books_attachments; +DROP VIEW IF EXISTS localized_AdminService_Authors; +DROP VIEW IF EXISTS localized_ReviewService_Statuses; +DROP VIEW IF EXISTS localized_CatalogService_Statuses; +DROP VIEW IF EXISTS localized_AdminService_Statuses; +DROP VIEW IF EXISTS localized_ReviewService_Currencies; +DROP VIEW IF EXISTS localized_ReviewService_Genres; +DROP VIEW IF EXISTS localized_CatalogService_Currencies; +DROP VIEW IF EXISTS localized_CatalogService_Genres; +DROP VIEW IF EXISTS localized_AdminService_Currencies; +DROP VIEW IF EXISTS localized_AdminService_Genres; +DROP VIEW IF EXISTS localized_ReviewService_Books; +DROP VIEW IF EXISTS localized_CatalogService_Books; +DROP VIEW IF EXISTS localized_AdminService_Languages; +DROP VIEW IF EXISTS localized_AdminService_Books; +DROP VIEW IF EXISTS ReviewService_DraftAdministrativeData; +DROP VIEW IF EXISTS NotesService_DraftAdministrativeData; +DROP VIEW IF EXISTS AdminService_DraftAdministrativeData; +DROP VIEW IF EXISTS localized_my_bookshop_Orders_changes; +DROP VIEW IF EXISTS localized_my_bookshop_Books_attachments; +DROP VIEW IF EXISTS localized_my_bookshop_Reviews; +DROP VIEW IF EXISTS localized_my_bookshop_OrderItems; +DROP VIEW IF EXISTS localized_my_bookshop_Orders; +DROP VIEW IF EXISTS localized_my_bookshop_Authors; +DROP VIEW IF EXISTS localized_sap_common_Currencies; +DROP VIEW IF EXISTS localized_sap_common_Languages; +DROP VIEW IF EXISTS localized_my_bookshop_Genres; +DROP VIEW IF EXISTS localized_my_bookshop_Books; +DROP VIEW IF EXISTS localized_Statuses; +DROP VIEW IF EXISTS ReviewService_Statuses_texts; +DROP VIEW IF EXISTS CatalogService_Statuses_texts; +DROP VIEW IF EXISTS AdminService_Statuses_texts; +DROP VIEW IF EXISTS ReviewService_Statuses; +DROP VIEW IF EXISTS ReviewService_Currencies_texts; +DROP VIEW IF EXISTS ReviewService_Genres_texts; +DROP VIEW IF EXISTS CatalogService_Statuses; +DROP VIEW IF EXISTS CatalogService_Currencies_texts; +DROP VIEW IF EXISTS CatalogService_Genres_texts; +DROP VIEW IF EXISTS AdminService_Changes; +DROP VIEW IF EXISTS AdminService_Statuses; +DROP VIEW IF EXISTS AdminService_Currencies_texts; +DROP VIEW IF EXISTS AdminService_Genres_texts; +DROP VIEW IF EXISTS ReviewService_Books_texts; +DROP VIEW IF EXISTS ReviewService_Books_attachments; +DROP VIEW IF EXISTS ReviewService_Currencies; +DROP VIEW IF EXISTS ReviewService_Genres; +DROP VIEW IF EXISTS CatalogService_Books_texts; +DROP VIEW IF EXISTS CatalogService_Books_attachments; +DROP VIEW IF EXISTS CatalogService_Currencies; +DROP VIEW IF EXISTS CatalogService_Genres; +DROP VIEW IF EXISTS AdminService_Languages_texts; +DROP VIEW IF EXISTS AdminService_Addresses; +DROP VIEW IF EXISTS AdminService_Orders_changes; +DROP VIEW IF EXISTS AdminService_OrderItems; +DROP VIEW IF EXISTS AdminService_Books_texts; +DROP VIEW IF EXISTS AdminService_Books_attachments; +DROP VIEW IF EXISTS AdminService_Currencies; +DROP VIEW IF EXISTS AdminService_Genres; +DROP VIEW IF EXISTS ReviewService_Authors; +DROP VIEW IF EXISTS ReviewService_Books; +DROP VIEW IF EXISTS ReviewService_Reviews; +DROP VIEW IF EXISTS NotesService_Notes; +DROP VIEW IF EXISTS CatalogService_Reviews; +DROP VIEW IF EXISTS CatalogService_Authors; +DROP VIEW IF EXISTS CatalogService_Books; +DROP VIEW IF EXISTS AdminService_Languages; +DROP VIEW IF EXISTS AdminService_Orders; +DROP VIEW IF EXISTS AdminService_Authors; +DROP VIEW IF EXISTS AdminService_Books; +DROP TABLE IF EXISTS ReviewService_Reviews_drafts; +DROP TABLE IF EXISTS NotesService_Notes_drafts; +DROP TABLE IF EXISTS AdminService_OrderItems_drafts; +DROP TABLE IF EXISTS AdminService_Orders_drafts; +DROP TABLE IF EXISTS AdminService_Books_texts_drafts; +DROP TABLE IF EXISTS AdminService_Books_attachments_drafts; +DROP TABLE IF EXISTS AdminService_Books_drafts; +DROP TABLE IF EXISTS DRAFT_DraftAdministrativeData; +DROP TABLE IF EXISTS sap_common_Currencies_texts; +DROP TABLE IF EXISTS sap_common_Languages_texts; +DROP TABLE IF EXISTS my_bookshop_Orders_changes; +DROP TABLE IF EXISTS my_bookshop_Genres_texts; +DROP TABLE IF EXISTS my_bookshop_Books_texts; +DROP TABLE IF EXISTS my_bookshop_Books_attachments; +DROP TABLE IF EXISTS Statuses_texts; +DROP TABLE IF EXISTS sap_changelog_Changes; +DROP TABLE IF EXISTS sap_common_Currencies; +DROP TABLE IF EXISTS sap_common_Languages; +DROP TABLE IF EXISTS cds_outbox_Messages; +DROP TABLE IF EXISTS my_bookshop_Notes; +DROP TABLE IF EXISTS my_bookshop_Reviews; +DROP TABLE IF EXISTS my_bookshop_OrderItems; +DROP TABLE IF EXISTS my_bookshop_Orders; +DROP TABLE IF EXISTS my_bookshop_Genres; +DROP TABLE IF EXISTS my_bookshop_Authors; +DROP TABLE IF EXISTS my_bookshop_Books; +DROP TABLE IF EXISTS cds_xt_Extensions; +DROP TABLE IF EXISTS my_bookshop_Addresses; +DROP TABLE IF EXISTS Statuses; + +CREATE TABLE Statuses ( + code NVARCHAR(255) NOT NULL, + text NVARCHAR(255), + PRIMARY KEY(code) +); + +CREATE TABLE my_bookshop_Addresses ( + ID NVARCHAR(10) NOT NULL, + businessPartner NVARCHAR(10) NOT NULL, + country NVARCHAR(3), + city NVARCHAR(40), + postalCode NVARCHAR(10), + street NVARCHAR(60), + houseNumber NVARCHAR(10), + tombstone BOOLEAN, + PRIMARY KEY(ID, businessPartner) +); + +CREATE TABLE cds_xt_Extensions ( + ID NVARCHAR(36) NOT NULL, + tag NVARCHAR(255), + csn NCLOB, + i18n NCLOB, + sources BINARY LARGE OBJECT, + activated NVARCHAR(255), + timestamp TIMESTAMP(7), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Books ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + modifiedAt TIMESTAMP(7), + modifiedBy NVARCHAR(255), + title NVARCHAR(111), + descr NVARCHAR(1111), + author_ID NVARCHAR(36), + genre_ID INTEGER, + stock INTEGER, + price DECIMAL(9, 2), + currency_code NVARCHAR(3), + rating DECIMAL(2, 1), + isReviewable BOOLEAN NOT NULL DEFAULT TRUE, + isbn NVARCHAR(40), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Authors ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + modifiedAt TIMESTAMP(7), + modifiedBy NVARCHAR(255), + name NVARCHAR(111), + dateOfBirth DATE, + dateOfDeath DATE, + placeOfBirth NVARCHAR(255), + placeOfDeath NVARCHAR(255), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Genres ( + name NVARCHAR(255), + descr NVARCHAR(1000), + ID INTEGER NOT NULL, + parent_ID INTEGER, + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Orders ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + modifiedAt TIMESTAMP(7), + modifiedBy NVARCHAR(255), + OrderNo NVARCHAR(255), + buyer NVARCHAR(255), + total DECIMAL(9, 2), + currency_code NVARCHAR(3), + shippingAddress_ID NVARCHAR(10), + shippingAddress_businessPartner NVARCHAR(10), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_OrderItems ( + ID NVARCHAR(36) NOT NULL, + parent_ID NVARCHAR(36), + book_ID NVARCHAR(36), + quantity INTEGER, + amount DECIMAL(9, 2), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Reviews ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + modifiedAt TIMESTAMP(7), + modifiedBy NVARCHAR(255), + book_ID NVARCHAR(36), + rating INTEGER, + title NVARCHAR(111), + text NVARCHAR(1111), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Notes ( + ID NVARCHAR(36) NOT NULL, + note NVARCHAR(255), + address_ID NVARCHAR(10), + address_businessPartner NVARCHAR(10), + PRIMARY KEY(ID) +); + +CREATE TABLE cds_outbox_Messages ( + ID NVARCHAR(36) NOT NULL, + timestamp TIMESTAMP(7), + target NVARCHAR(255), + msg NCLOB, + attempts INTEGER DEFAULT 0, + "PARTITION" INTEGER DEFAULT 0, + lastError NCLOB, + lastAttemptTimestamp TIMESTAMP(7), + PRIMARY KEY(ID) +); + +CREATE TABLE sap_common_Languages ( + name NVARCHAR(255), + descr NVARCHAR(1000), + code NVARCHAR(14) NOT NULL, + PRIMARY KEY(code) +); + +CREATE TABLE sap_common_Currencies ( + name NVARCHAR(255), + descr NVARCHAR(1000), + code NVARCHAR(3) NOT NULL, + symbol NVARCHAR(5), + minorUnit SMALLINT, + PRIMARY KEY(code) +); + +CREATE TABLE sap_changelog_Changes ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + changeLogID NVARCHAR(36), + rootEntity NVARCHAR(255), + rootIdentifier NVARCHAR(255), + attribute NVARCHAR(255), + valueChangedFrom NVARCHAR(5000), + valueChangedTo NVARCHAR(5000), + valueDataType NVARCHAR(255), + targetIdentifier NVARCHAR(255), + targetEntity NVARCHAR(255), + path NVARCHAR(5000), + modification NVARCHAR(255), + PRIMARY KEY(ID) +); + +CREATE TABLE Statuses_texts ( + locale NVARCHAR(14) NOT NULL, + code NVARCHAR(255) NOT NULL, + text NVARCHAR(255), + PRIMARY KEY(locale, code) +); + +CREATE TABLE my_bookshop_Books_attachments ( + up__ID NVARCHAR(36) NOT NULL, + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + modifiedAt TIMESTAMP(7), + modifiedBy NVARCHAR(255), + content BINARY LARGE OBJECT, + mimeType NVARCHAR(255), + fileName NVARCHAR(255), + contentId NVARCHAR(255), + status NVARCHAR(255), + scannedAt TIMESTAMP(7), + note NVARCHAR(255), + folderId NVARCHAR(255), + repositoryId NVARCHAR(255), + objectId NVARCHAR(255), + PRIMARY KEY(up__ID, ID) +); + +CREATE TABLE my_bookshop_Books_texts ( + ID_texts NVARCHAR(36) NOT NULL, + locale NVARCHAR(14), + ID NVARCHAR(36), + title NVARCHAR(111), + descr NVARCHAR(1111), + PRIMARY KEY(ID_texts), + CONSTRAINT my_bookshop_Books_texts_locale UNIQUE (locale, ID) +); + +CREATE TABLE my_bookshop_Genres_texts ( + locale NVARCHAR(14) NOT NULL, + name NVARCHAR(255), + descr NVARCHAR(1000), + ID INTEGER NOT NULL, + PRIMARY KEY(locale, ID) +); + +CREATE TABLE my_bookshop_Orders_changes ( + up__ID NVARCHAR(36) NOT NULL, + change_ID NVARCHAR(36) NOT NULL, + PRIMARY KEY(up__ID, change_ID) +); + +CREATE TABLE sap_common_Languages_texts ( + locale NVARCHAR(14) NOT NULL, + name NVARCHAR(255), + descr NVARCHAR(1000), + code NVARCHAR(14) NOT NULL, + PRIMARY KEY(locale, code) +); + +CREATE TABLE sap_common_Currencies_texts ( + locale NVARCHAR(14) NOT NULL, + name NVARCHAR(255), + descr NVARCHAR(1000), + code NVARCHAR(3) NOT NULL, + PRIMARY KEY(locale, code) +); + +CREATE TABLE DRAFT_DraftAdministrativeData ( + DraftUUID NVARCHAR(36) NOT NULL, + CreationDateTime TIMESTAMP(7), + CreatedByUser NVARCHAR(256), + DraftIsCreatedByMe BOOLEAN, + LastChangeDateTime TIMESTAMP(7), + LastChangedByUser NVARCHAR(256), + InProcessByUser NVARCHAR(256), + DraftIsProcessedByMe BOOLEAN, + PRIMARY KEY(DraftUUID) +); + +CREATE TABLE AdminService_Books_drafts ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7) NULL, + createdBy NVARCHAR(255) NULL, + modifiedAt TIMESTAMP(7) NULL, + modifiedBy NVARCHAR(255) NULL, + title NVARCHAR(111) NULL, + descr NVARCHAR(1111) NULL, + author_ID NVARCHAR(36) NULL, + genre_ID INTEGER NULL, + stock INTEGER NULL, + price DECIMAL(9, 2) NULL, + currency_code NVARCHAR(3) NULL, + rating DECIMAL(2, 1) NULL, + isReviewable BOOLEAN NULL DEFAULT TRUE, + isbn NVARCHAR(40) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID) +); + +CREATE TABLE AdminService_Books_attachments_drafts ( + up__ID NVARCHAR(36) NOT NULL, + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7) NULL, + createdBy NVARCHAR(255) NULL, + modifiedAt TIMESTAMP(7) NULL, + modifiedBy NVARCHAR(255) NULL, + content BINARY LARGE OBJECT NULL, + mimeType NVARCHAR(255) NULL, + fileName NVARCHAR(255) NULL, + contentId NVARCHAR(255) NULL, + status NVARCHAR(255) NULL, + scannedAt TIMESTAMP(7) NULL, + note NVARCHAR(255) NULL, + folderId NVARCHAR(255) NULL, + repositoryId NVARCHAR(255) NULL, + objectId NVARCHAR(255) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(up__ID, ID) +); + +CREATE TABLE AdminService_Books_texts_drafts ( + ID_texts NVARCHAR(36) NOT NULL, + locale NVARCHAR(14) NULL, + ID NVARCHAR(36) NULL, + title NVARCHAR(111) NULL, + descr NVARCHAR(1111) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID_texts) +); + +CREATE TABLE AdminService_Orders_drafts ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7) NULL, + createdBy NVARCHAR(255) NULL, + modifiedAt TIMESTAMP(7) NULL, + modifiedBy NVARCHAR(255) NULL, + OrderNo NVARCHAR(255) NULL, + buyer NVARCHAR(255) NULL, + total DECIMAL(9, 2) NULL, + currency_code NVARCHAR(3) NULL, + shippingAddress_ID NVARCHAR(10) NULL, + shippingAddress_businessPartner NVARCHAR(10) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID) +); + +CREATE TABLE AdminService_OrderItems_drafts ( + ID NVARCHAR(36) NOT NULL, + parent_ID NVARCHAR(36) NULL, + book_ID NVARCHAR(36) NULL, + quantity INTEGER NULL, + amount DECIMAL(9, 2) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID) +); + +CREATE TABLE NotesService_Notes_drafts ( + ID NVARCHAR(36) NOT NULL, + note NVARCHAR(255) NULL, + address_ID NVARCHAR(10) NULL, + address_businessPartner NVARCHAR(10) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID) +); + +CREATE TABLE ReviewService_Reviews_drafts ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7) NULL, + createdBy NVARCHAR(255) NULL, + modifiedAt TIMESTAMP(7) NULL, + modifiedBy NVARCHAR(255) NULL, + book_ID NVARCHAR(36) NULL, + rating INTEGER NULL, + title NVARCHAR(111) NULL, + text NVARCHAR(1111) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID) +); + +CREATE VIEW AdminService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.createdBy, + Books_0.modifiedAt, + Books_0.modifiedBy, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM my_bookshop_Books AS Books_0; + +CREATE VIEW AdminService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM my_bookshop_Authors AS Authors_0; + +CREATE VIEW AdminService_Orders AS SELECT + Orders_0.ID, + Orders_0.createdAt, + Orders_0.createdBy, + Orders_0.modifiedAt, + Orders_0.modifiedBy, + Orders_0.OrderNo, + Orders_0.buyer, + Orders_0.total, + Orders_0.currency_code, + Orders_0.shippingAddress_ID, + Orders_0.shippingAddress_businessPartner +FROM my_bookshop_Orders AS Orders_0; + +CREATE VIEW AdminService_Languages AS SELECT + CommonLanguages_0.name, + CommonLanguages_0.descr, + CommonLanguages_0.code +FROM sap_common_Languages AS CommonLanguages_0; + +CREATE VIEW CatalogService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.modifiedAt, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM my_bookshop_Books AS Books_0; + +CREATE VIEW CatalogService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM my_bookshop_Authors AS Authors_0; + +CREATE VIEW CatalogService_Reviews AS SELECT + Reviews_0.ID, + Reviews_0.createdAt, + Reviews_0.createdBy, + Reviews_0.modifiedAt, + Reviews_0.modifiedBy, + Reviews_0.book_ID, + Reviews_0.rating, + Reviews_0.title, + Reviews_0.text +FROM my_bookshop_Reviews AS Reviews_0; + +CREATE VIEW NotesService_Notes AS SELECT + Notes_0.ID, + Notes_0.note, + Notes_0.address_ID, + Notes_0.address_businessPartner +FROM my_bookshop_Notes AS Notes_0; + +CREATE VIEW ReviewService_Reviews AS SELECT + Reviews_0.ID, + Reviews_0.createdAt, + Reviews_0.createdBy, + Reviews_0.modifiedAt, + Reviews_0.modifiedBy, + Reviews_0.book_ID, + Reviews_0.rating, + Reviews_0.title, + Reviews_0.text +FROM my_bookshop_Reviews AS Reviews_0; + +CREATE VIEW ReviewService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.modifiedAt, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM my_bookshop_Books AS Books_0; + +CREATE VIEW ReviewService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM my_bookshop_Authors AS Authors_0; + +CREATE VIEW AdminService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM my_bookshop_Genres AS Genres_0; + +CREATE VIEW AdminService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM sap_common_Currencies AS Currencies_0; + +CREATE VIEW AdminService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW AdminService_Books_texts AS SELECT + texts_0.ID_texts, + texts_0.locale, + texts_0.ID, + texts_0.title, + texts_0.descr +FROM my_bookshop_Books_texts AS texts_0; + +CREATE VIEW AdminService_OrderItems AS SELECT + OrderItems_0.ID, + OrderItems_0.parent_ID, + OrderItems_0.book_ID, + OrderItems_0.quantity, + OrderItems_0.amount +FROM my_bookshop_OrderItems AS OrderItems_0; + +CREATE VIEW AdminService_Orders_changes AS SELECT + changes_0.up__ID, + changes_0.change_ID +FROM my_bookshop_Orders_changes AS changes_0; + +CREATE VIEW AdminService_Addresses AS SELECT + Addresses_0.ID, + Addresses_0.businessPartner, + Addresses_0.country, + Addresses_0.city, + Addresses_0.postalCode, + Addresses_0.street, + Addresses_0.houseNumber, + Addresses_0.tombstone +FROM my_bookshop_Addresses AS Addresses_0; + +CREATE VIEW AdminService_Languages_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.code +FROM sap_common_Languages_texts AS texts_0; + +CREATE VIEW CatalogService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM my_bookshop_Genres AS Genres_0; + +CREATE VIEW CatalogService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM sap_common_Currencies AS Currencies_0; + +CREATE VIEW CatalogService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW CatalogService_Books_texts AS SELECT + texts_0.ID_texts, + texts_0.locale, + texts_0.ID, + texts_0.title, + texts_0.descr +FROM my_bookshop_Books_texts AS texts_0; + +CREATE VIEW ReviewService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM my_bookshop_Genres AS Genres_0; + +CREATE VIEW ReviewService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM sap_common_Currencies AS Currencies_0; + +CREATE VIEW ReviewService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW ReviewService_Books_texts AS SELECT + texts_0.ID_texts, + texts_0.locale, + texts_0.ID, + texts_0.title, + texts_0.descr +FROM my_bookshop_Books_texts AS texts_0; + +CREATE VIEW AdminService_Genres_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.ID +FROM my_bookshop_Genres_texts AS texts_0; + +CREATE VIEW AdminService_Currencies_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.code +FROM sap_common_Currencies_texts AS texts_0; + +CREATE VIEW AdminService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM Statuses AS Statuses_0; + +CREATE VIEW AdminService_Changes AS SELECT + Changes_0.ID, + Changes_0.createdAt, + Changes_0.createdBy, + Changes_0.changeLogID, + Changes_0.rootEntity, + Changes_0.rootIdentifier, + Changes_0.attribute, + Changes_0.valueChangedFrom, + Changes_0.valueChangedTo, + Changes_0.valueDataType, + Changes_0.targetIdentifier, + Changes_0.targetEntity, + Changes_0.path, + Changes_0.modification +FROM sap_changelog_Changes AS Changes_0; + +CREATE VIEW CatalogService_Genres_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.ID +FROM my_bookshop_Genres_texts AS texts_0; + +CREATE VIEW CatalogService_Currencies_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.code +FROM sap_common_Currencies_texts AS texts_0; + +CREATE VIEW CatalogService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM Statuses AS Statuses_0; + +CREATE VIEW ReviewService_Genres_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.ID +FROM my_bookshop_Genres_texts AS texts_0; + +CREATE VIEW ReviewService_Currencies_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.code +FROM sap_common_Currencies_texts AS texts_0; + +CREATE VIEW ReviewService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM Statuses AS Statuses_0; + +CREATE VIEW AdminService_Statuses_texts AS SELECT + texts_0.locale, + texts_0.code, + texts_0.text +FROM Statuses_texts AS texts_0; + +CREATE VIEW CatalogService_Statuses_texts AS SELECT + texts_0.locale, + texts_0.code, + texts_0.text +FROM Statuses_texts AS texts_0; + +CREATE VIEW ReviewService_Statuses_texts AS SELECT + texts_0.locale, + texts_0.code, + texts_0.text +FROM Statuses_texts AS texts_0; + +CREATE VIEW localized_Statuses AS SELECT + L_0.code, + coalesce(localized_1.text, L_0.text) AS text +FROM (Statuses AS L_0 LEFT JOIN Statuses_texts AS localized_1 ON localized_1.code = L_0.code AND localized_1.locale = @locale); + +CREATE VIEW localized_my_bookshop_Books AS SELECT + L_0.ID, + L_0.createdAt, + L_0.createdBy, + L_0.modifiedAt, + L_0.modifiedBy, + coalesce(localized_1.title, L_0.title) AS title, + coalesce(localized_1.descr, L_0.descr) AS descr, + L_0.author_ID, + L_0.genre_ID, + L_0.stock, + L_0.price, + L_0.currency_code, + L_0.rating, + L_0.isReviewable, + L_0.isbn +FROM (my_bookshop_Books AS L_0 LEFT JOIN my_bookshop_Books_texts AS localized_1 ON localized_1.ID = L_0.ID AND localized_1.locale = @locale); + +CREATE VIEW localized_my_bookshop_Genres AS SELECT + coalesce(localized_1.name, L_0.name) AS name, + coalesce(localized_1.descr, L_0.descr) AS descr, + L_0.ID, + L_0.parent_ID +FROM (my_bookshop_Genres AS L_0 LEFT JOIN my_bookshop_Genres_texts AS localized_1 ON localized_1.ID = L_0.ID AND localized_1.locale = @locale); + +CREATE VIEW localized_sap_common_Languages AS SELECT + coalesce(localized_1.name, L_0.name) AS name, + coalesce(localized_1.descr, L_0.descr) AS descr, + L_0.code +FROM (sap_common_Languages AS L_0 LEFT JOIN sap_common_Languages_texts AS localized_1 ON localized_1.code = L_0.code AND localized_1.locale = @locale); + +CREATE VIEW localized_sap_common_Currencies AS SELECT + coalesce(localized_1.name, L_0.name) AS name, + coalesce(localized_1.descr, L_0.descr) AS descr, + L_0.code, + L_0.symbol, + L_0.minorUnit +FROM (sap_common_Currencies AS L_0 LEFT JOIN sap_common_Currencies_texts AS localized_1 ON localized_1.code = L_0.code AND localized_1.locale = @locale); + +CREATE VIEW localized_my_bookshop_Authors AS SELECT + L.ID, + L.createdAt, + L.createdBy, + L.modifiedAt, + L.modifiedBy, + L.name, + L.dateOfBirth, + L.dateOfDeath, + L.placeOfBirth, + L.placeOfDeath +FROM my_bookshop_Authors AS L; + +CREATE VIEW localized_my_bookshop_Orders AS SELECT + L.ID, + L.createdAt, + L.createdBy, + L.modifiedAt, + L.modifiedBy, + L.OrderNo, + L.buyer, + L.total, + L.currency_code, + L.shippingAddress_ID, + L.shippingAddress_businessPartner +FROM my_bookshop_Orders AS L; + +CREATE VIEW localized_my_bookshop_OrderItems AS SELECT + L.ID, + L.parent_ID, + L.book_ID, + L.quantity, + L.amount +FROM my_bookshop_OrderItems AS L; + +CREATE VIEW localized_my_bookshop_Reviews AS SELECT + L.ID, + L.createdAt, + L.createdBy, + L.modifiedAt, + L.modifiedBy, + L.book_ID, + L.rating, + L.title, + L.text +FROM my_bookshop_Reviews AS L; + +CREATE VIEW localized_my_bookshop_Books_attachments AS SELECT + L.up__ID, + L.ID, + L.createdAt, + L.createdBy, + L.modifiedAt, + L.modifiedBy, + L.content, + L.mimeType, + L.fileName, + L.contentId, + L.status, + L.scannedAt, + L.note, + L.folderId, + L.repositoryId, + L.objectId +FROM my_bookshop_Books_attachments AS L; + +CREATE VIEW localized_my_bookshop_Orders_changes AS SELECT + L.up__ID, + L.change_ID +FROM my_bookshop_Orders_changes AS L; + +CREATE VIEW AdminService_DraftAdministrativeData AS SELECT + DraftAdministrativeData.DraftUUID, + DraftAdministrativeData.CreationDateTime, + DraftAdministrativeData.CreatedByUser, + DraftAdministrativeData.DraftIsCreatedByMe, + DraftAdministrativeData.LastChangeDateTime, + DraftAdministrativeData.LastChangedByUser, + DraftAdministrativeData.InProcessByUser, + DraftAdministrativeData.DraftIsProcessedByMe +FROM DRAFT_DraftAdministrativeData AS DraftAdministrativeData; + +CREATE VIEW NotesService_DraftAdministrativeData AS SELECT + DraftAdministrativeData.DraftUUID, + DraftAdministrativeData.CreationDateTime, + DraftAdministrativeData.CreatedByUser, + DraftAdministrativeData.DraftIsCreatedByMe, + DraftAdministrativeData.LastChangeDateTime, + DraftAdministrativeData.LastChangedByUser, + DraftAdministrativeData.InProcessByUser, + DraftAdministrativeData.DraftIsProcessedByMe +FROM DRAFT_DraftAdministrativeData AS DraftAdministrativeData; + +CREATE VIEW ReviewService_DraftAdministrativeData AS SELECT + DraftAdministrativeData.DraftUUID, + DraftAdministrativeData.CreationDateTime, + DraftAdministrativeData.CreatedByUser, + DraftAdministrativeData.DraftIsCreatedByMe, + DraftAdministrativeData.LastChangeDateTime, + DraftAdministrativeData.LastChangedByUser, + DraftAdministrativeData.InProcessByUser, + DraftAdministrativeData.DraftIsProcessedByMe +FROM DRAFT_DraftAdministrativeData AS DraftAdministrativeData; + +CREATE VIEW localized_AdminService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.createdBy, + Books_0.modifiedAt, + Books_0.modifiedBy, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM localized_my_bookshop_Books AS Books_0; + +CREATE VIEW localized_AdminService_Languages AS SELECT + CommonLanguages_0.name, + CommonLanguages_0.descr, + CommonLanguages_0.code +FROM localized_sap_common_Languages AS CommonLanguages_0; + +CREATE VIEW localized_CatalogService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.modifiedAt, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM localized_my_bookshop_Books AS Books_0; + +CREATE VIEW localized_ReviewService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.modifiedAt, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM localized_my_bookshop_Books AS Books_0; + +CREATE VIEW localized_AdminService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM localized_my_bookshop_Genres AS Genres_0; + +CREATE VIEW localized_AdminService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM localized_sap_common_Currencies AS Currencies_0; + +CREATE VIEW localized_CatalogService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM localized_my_bookshop_Genres AS Genres_0; + +CREATE VIEW localized_CatalogService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM localized_sap_common_Currencies AS Currencies_0; + +CREATE VIEW localized_ReviewService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM localized_my_bookshop_Genres AS Genres_0; + +CREATE VIEW localized_ReviewService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM localized_sap_common_Currencies AS Currencies_0; + +CREATE VIEW localized_AdminService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM localized_Statuses AS Statuses_0; + +CREATE VIEW localized_CatalogService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM localized_Statuses AS Statuses_0; + +CREATE VIEW localized_ReviewService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM localized_Statuses AS Statuses_0; + +CREATE VIEW localized_AdminService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM localized_my_bookshop_Authors AS Authors_0; + +CREATE VIEW localized_AdminService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM localized_my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW localized_AdminService_OrderItems AS SELECT + OrderItems_0.ID, + OrderItems_0.parent_ID, + OrderItems_0.book_ID, + OrderItems_0.quantity, + OrderItems_0.amount +FROM localized_my_bookshop_OrderItems AS OrderItems_0; + +CREATE VIEW localized_CatalogService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM localized_my_bookshop_Authors AS Authors_0; + +CREATE VIEW localized_CatalogService_Reviews AS SELECT + Reviews_0.ID, + Reviews_0.createdAt, + Reviews_0.createdBy, + Reviews_0.modifiedAt, + Reviews_0.modifiedBy, + Reviews_0.book_ID, + Reviews_0.rating, + Reviews_0.title, + Reviews_0.text +FROM localized_my_bookshop_Reviews AS Reviews_0; + +CREATE VIEW localized_CatalogService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM localized_my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW localized_ReviewService_Reviews AS SELECT + Reviews_0.ID, + Reviews_0.createdAt, + Reviews_0.createdBy, + Reviews_0.modifiedAt, + Reviews_0.modifiedBy, + Reviews_0.book_ID, + Reviews_0.rating, + Reviews_0.title, + Reviews_0.text +FROM localized_my_bookshop_Reviews AS Reviews_0; + +CREATE VIEW localized_ReviewService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM localized_my_bookshop_Authors AS Authors_0; + +CREATE VIEW localized_ReviewService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM localized_my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW localized_AdminService_Orders AS SELECT + Orders_0.ID, + Orders_0.createdAt, + Orders_0.createdBy, + Orders_0.modifiedAt, + Orders_0.modifiedBy, + Orders_0.OrderNo, + Orders_0.buyer, + Orders_0.total, + Orders_0.currency_code, + Orders_0.shippingAddress_ID, + Orders_0.shippingAddress_businessPartner +FROM localized_my_bookshop_Orders AS Orders_0; + +CREATE VIEW localized_AdminService_Orders_changes AS SELECT + changes_0.up__ID, + changes_0.change_ID +FROM localized_my_bookshop_Orders_changes AS changes_0; + diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/schema.sql b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/schema.sql new file mode 100644 index 000000000..08469b10c --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/schema.sql @@ -0,0 +1,1963 @@ + +DROP VIEW IF EXISTS localized_AdminService_Orders_changes; +DROP VIEW IF EXISTS localized_AdminService_Orders; +DROP VIEW IF EXISTS localized_ReviewService_Books_attachments; +DROP VIEW IF EXISTS localized_ReviewService_Authors; +DROP VIEW IF EXISTS localized_ReviewService_Reviews; +DROP VIEW IF EXISTS localized_CatalogService_Books_attachments; +DROP VIEW IF EXISTS localized_CatalogService_Reviews; +DROP VIEW IF EXISTS localized_CatalogService_Authors; +DROP VIEW IF EXISTS localized_AdminService_OrderItems; +DROP VIEW IF EXISTS localized_AdminService_Books_attachments; +DROP VIEW IF EXISTS localized_AdminService_Authors; +DROP VIEW IF EXISTS localized_ReviewService_Statuses; +DROP VIEW IF EXISTS localized_CatalogService_Statuses; +DROP VIEW IF EXISTS localized_AdminService_Statuses; +DROP VIEW IF EXISTS localized_ReviewService_Currencies; +DROP VIEW IF EXISTS localized_ReviewService_Genres; +DROP VIEW IF EXISTS localized_CatalogService_Currencies; +DROP VIEW IF EXISTS localized_CatalogService_Genres; +DROP VIEW IF EXISTS localized_AdminService_Currencies; +DROP VIEW IF EXISTS localized_AdminService_Genres; +DROP VIEW IF EXISTS localized_ReviewService_Books; +DROP VIEW IF EXISTS localized_CatalogService_Books; +DROP VIEW IF EXISTS localized_AdminService_Languages; +DROP VIEW IF EXISTS localized_AdminService_Books; +DROP VIEW IF EXISTS NotesService_Addresses; +DROP VIEW IF EXISTS ReviewService_DraftAdministrativeData; +DROP VIEW IF EXISTS NotesService_DraftAdministrativeData; +DROP VIEW IF EXISTS AdminService_DraftAdministrativeData; +DROP VIEW IF EXISTS localized_my_bookshop_Orders_changes; +DROP VIEW IF EXISTS localized_my_bookshop_Books_attachments; +DROP VIEW IF EXISTS localized_my_bookshop_Reviews; +DROP VIEW IF EXISTS localized_my_bookshop_OrderItems; +DROP VIEW IF EXISTS localized_my_bookshop_Orders; +DROP VIEW IF EXISTS localized_my_bookshop_Authors; +DROP VIEW IF EXISTS localized_sap_common_Currencies; +DROP VIEW IF EXISTS localized_sap_common_Languages; +DROP VIEW IF EXISTS localized_my_bookshop_Genres; +DROP VIEW IF EXISTS localized_my_bookshop_Books; +DROP VIEW IF EXISTS localized_Statuses; +DROP VIEW IF EXISTS ReviewService_Statuses_texts; +DROP VIEW IF EXISTS CatalogService_Statuses_texts; +DROP VIEW IF EXISTS AdminService_Statuses_texts; +DROP VIEW IF EXISTS ReviewService_Statuses; +DROP VIEW IF EXISTS ReviewService_Currencies_texts; +DROP VIEW IF EXISTS ReviewService_Genres_texts; +DROP VIEW IF EXISTS CatalogService_Statuses; +DROP VIEW IF EXISTS CatalogService_Currencies_texts; +DROP VIEW IF EXISTS CatalogService_Genres_texts; +DROP VIEW IF EXISTS AdminService_Changes; +DROP VIEW IF EXISTS AdminService_Statuses; +DROP VIEW IF EXISTS AdminService_Currencies_texts; +DROP VIEW IF EXISTS AdminService_Genres_texts; +DROP VIEW IF EXISTS ReviewService_Books_texts; +DROP VIEW IF EXISTS ReviewService_Books_attachments; +DROP VIEW IF EXISTS ReviewService_Currencies; +DROP VIEW IF EXISTS ReviewService_Genres; +DROP VIEW IF EXISTS CatalogService_Books_texts; +DROP VIEW IF EXISTS CatalogService_Books_attachments; +DROP VIEW IF EXISTS CatalogService_Currencies; +DROP VIEW IF EXISTS CatalogService_Genres; +DROP VIEW IF EXISTS AdminService_Languages_texts; +DROP VIEW IF EXISTS AdminService_Addresses; +DROP VIEW IF EXISTS AdminService_Orders_changes; +DROP VIEW IF EXISTS AdminService_OrderItems; +DROP VIEW IF EXISTS AdminService_Books_texts; +DROP VIEW IF EXISTS AdminService_Books_attachments; +DROP VIEW IF EXISTS AdminService_Currencies; +DROP VIEW IF EXISTS AdminService_Genres; +DROP VIEW IF EXISTS ReviewService_Authors; +DROP VIEW IF EXISTS ReviewService_Books; +DROP VIEW IF EXISTS ReviewService_Reviews; +DROP VIEW IF EXISTS NotesService_Notes; +DROP VIEW IF EXISTS my_bookshop_NoteableAddresses; +DROP VIEW IF EXISTS CatalogService_Reviews; +DROP VIEW IF EXISTS CatalogService_Authors; +DROP VIEW IF EXISTS CatalogService_Books; +DROP VIEW IF EXISTS AdminService_Languages; +DROP VIEW IF EXISTS AdminService_Orders; +DROP VIEW IF EXISTS AdminService_Authors; +DROP VIEW IF EXISTS AdminService_Books; +DROP TABLE IF EXISTS ReviewService_Reviews_drafts; +DROP TABLE IF EXISTS NotesService_Notes_drafts; +DROP TABLE IF EXISTS AdminService_OrderItems_drafts; +DROP TABLE IF EXISTS AdminService_Orders_drafts; +DROP TABLE IF EXISTS AdminService_Books_texts_drafts; +DROP TABLE IF EXISTS AdminService_Books_attachments_drafts; +DROP TABLE IF EXISTS AdminService_Books_drafts; +DROP TABLE IF EXISTS DRAFT_DraftAdministrativeData; +DROP TABLE IF EXISTS sap_common_Currencies_texts; +DROP TABLE IF EXISTS sap_common_Languages_texts; +DROP TABLE IF EXISTS my_bookshop_Orders_changes; +DROP TABLE IF EXISTS my_bookshop_Genres_texts; +DROP TABLE IF EXISTS my_bookshop_Books_texts; +DROP TABLE IF EXISTS my_bookshop_Books_attachments; +DROP TABLE IF EXISTS Statuses_texts; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_SupplierWithHoldingTax; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_SupplierPurchasingOrg; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_SupplierPartnerFunc; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_SupplierDunning; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_SupplierCompany; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_Supplier; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_CustSalesPartnerFunc; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_CustomerWithHoldingTax; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_CustomerSalesAreaTax; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_CustomerSalesArea; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_CustomerDunning; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_CustomerCompany; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_Customer; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BusinessPartnerTaxNumber; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BusinessPartnerRole; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BusinessPartnerContact; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BusinessPartnerBank; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BusinessPartnerAddress; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BusinessPartner; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BuPaIndustry; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BuPaIdentification; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BuPaAddressUsage; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BPContactToFuncAndDept; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BPContactToAddress; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_AddressPhoneNumber; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_AddressHomePageURL; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_AddressFaxNumber; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_AddressEmailAddress; +DROP TABLE IF EXISTS sap_changelog_Changes; +DROP TABLE IF EXISTS sap_common_Currencies; +DROP TABLE IF EXISTS sap_common_Languages; +DROP TABLE IF EXISTS cds_outbox_Messages; +DROP TABLE IF EXISTS my_bookshop_Notes; +DROP TABLE IF EXISTS my_bookshop_Reviews; +DROP TABLE IF EXISTS my_bookshop_OrderItems; +DROP TABLE IF EXISTS my_bookshop_Orders; +DROP TABLE IF EXISTS my_bookshop_Genres; +DROP TABLE IF EXISTS my_bookshop_Authors; +DROP TABLE IF EXISTS my_bookshop_Books; +DROP TABLE IF EXISTS cds_xt_Extensions; +DROP TABLE IF EXISTS my_bookshop_Addresses; +DROP TABLE IF EXISTS Statuses; +DROP TABLE IF EXISTS AdminService_Upload; + +CREATE TABLE AdminService_Upload ( + csv BINARY LARGE OBJECT +); + +CREATE TABLE Statuses ( + code NVARCHAR(255) NOT NULL, + text NVARCHAR(255), + PRIMARY KEY(code) +); + +CREATE TABLE my_bookshop_Addresses ( + ID NVARCHAR(10) NOT NULL, + businessPartner NVARCHAR(10) NOT NULL, + country NVARCHAR(3), + city NVARCHAR(40), + postalCode NVARCHAR(10), + street NVARCHAR(60), + houseNumber NVARCHAR(10), + tombstone BOOLEAN, + PRIMARY KEY(ID, businessPartner) +); + +CREATE TABLE cds_xt_Extensions ( + ID NVARCHAR(36) NOT NULL, + tag NVARCHAR(255), + csn NCLOB, + i18n NCLOB, + sources BINARY LARGE OBJECT, + activated NVARCHAR(255), + timestamp TIMESTAMP(7), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Books ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + modifiedAt TIMESTAMP(7), + modifiedBy NVARCHAR(255), + title NVARCHAR(111), + descr NVARCHAR(1111), + author_ID NVARCHAR(36), + genre_ID INTEGER, + stock INTEGER, + price DECIMAL(9, 2), + currency_code NVARCHAR(3), + rating DECIMAL(2, 1), + isReviewable BOOLEAN NOT NULL DEFAULT TRUE, + isbn NVARCHAR(40), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Authors ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + modifiedAt TIMESTAMP(7), + modifiedBy NVARCHAR(255), + name NVARCHAR(111), + dateOfBirth DATE, + dateOfDeath DATE, + placeOfBirth NVARCHAR(255), + placeOfDeath NVARCHAR(255), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Genres ( + name NVARCHAR(255), + descr NVARCHAR(1000), + ID INTEGER NOT NULL, + parent_ID INTEGER, + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Orders ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + modifiedAt TIMESTAMP(7), + modifiedBy NVARCHAR(255), + OrderNo NVARCHAR(255), + buyer NVARCHAR(255), + total DECIMAL(9, 2), + currency_code NVARCHAR(3), + shippingAddress_ID NVARCHAR(10), + shippingAddress_businessPartner NVARCHAR(10), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_OrderItems ( + ID NVARCHAR(36) NOT NULL, + parent_ID NVARCHAR(36), + book_ID NVARCHAR(36), + quantity INTEGER, + amount DECIMAL(9, 2), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Reviews ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + modifiedAt TIMESTAMP(7), + modifiedBy NVARCHAR(255), + book_ID NVARCHAR(36), + rating INTEGER, + title NVARCHAR(111), + text NVARCHAR(1111), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Notes ( + ID NVARCHAR(36) NOT NULL, + note NVARCHAR(255), + address_ID NVARCHAR(10), + address_businessPartner NVARCHAR(10), + PRIMARY KEY(ID) +); + +CREATE TABLE cds_outbox_Messages ( + ID NVARCHAR(36) NOT NULL, + timestamp TIMESTAMP(7), + target NVARCHAR(255), + msg NCLOB, + attempts INTEGER DEFAULT 0, + "PARTITION" INTEGER DEFAULT 0, + lastError NCLOB, + lastAttemptTimestamp TIMESTAMP(7), + PRIMARY KEY(ID) +); + +CREATE TABLE sap_common_Languages ( + name NVARCHAR(255), + descr NVARCHAR(1000), + code NVARCHAR(14) NOT NULL, + PRIMARY KEY(code) +); + +CREATE TABLE sap_common_Currencies ( + name NVARCHAR(255), + descr NVARCHAR(1000), + code NVARCHAR(3) NOT NULL, + symbol NVARCHAR(5), + minorUnit SMALLINT, + PRIMARY KEY(code) +); + +CREATE TABLE sap_changelog_Changes ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + changeLogID NVARCHAR(36), + rootEntity NVARCHAR(255), + rootIdentifier NVARCHAR(255), + attribute NVARCHAR(255), + valueChangedFrom NVARCHAR(5000), + valueChangedTo NVARCHAR(5000), + valueDataType NVARCHAR(255), + targetIdentifier NVARCHAR(255), + targetEntity NVARCHAR(255), + path NVARCHAR(5000), + modification NVARCHAR(255), + PRIMARY KEY(ID) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_AddressEmailAddress ( + AddressID NVARCHAR(10) NOT NULL, + Person NVARCHAR(10) NOT NULL, + OrdinalNumber NVARCHAR(3) NOT NULL, + IsDefaultEmailAddress BOOLEAN, + EmailAddress NVARCHAR(241), + SearchEmailAddress NVARCHAR(20), + AddressCommunicationRemarkText NVARCHAR(50), + PRIMARY KEY(AddressID, Person, OrdinalNumber) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_AddressFaxNumber ( + AddressID NVARCHAR(10) NOT NULL, + Person NVARCHAR(10) NOT NULL, + OrdinalNumber NVARCHAR(3) NOT NULL, + IsDefaultFaxNumber BOOLEAN, + FaxCountry NVARCHAR(3), + FaxNumber NVARCHAR(30), + FaxNumberExtension NVARCHAR(10), + InternationalFaxNumber NVARCHAR(30), + AddressCommunicationRemarkText NVARCHAR(50), + PRIMARY KEY(AddressID, Person, OrdinalNumber) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_AddressHomePageURL ( + AddressID NVARCHAR(10) NOT NULL, + Person NVARCHAR(10) NOT NULL, + OrdinalNumber NVARCHAR(3) NOT NULL, + ValidityStartDate DATE NOT NULL, + IsDefaultURLAddress BOOLEAN NOT NULL, + SearchURLAddress NVARCHAR(50), + AddressCommunicationRemarkText NVARCHAR(50), + URLFieldLength INTEGER, + WebsiteURL NVARCHAR(2048), + PRIMARY KEY(AddressID, Person, OrdinalNumber, ValidityStartDate, IsDefaultURLAddress) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_AddressPhoneNumber ( + AddressID NVARCHAR(10) NOT NULL, + Person NVARCHAR(10) NOT NULL, + OrdinalNumber NVARCHAR(3) NOT NULL, + DestinationLocationCountry NVARCHAR(3), + IsDefaultPhoneNumber BOOLEAN, + PhoneNumber NVARCHAR(30), + PhoneNumberExtension NVARCHAR(10), + InternationalPhoneNumber NVARCHAR(30), + PhoneNumberType NVARCHAR(1), + AddressCommunicationRemarkText NVARCHAR(50), + PRIMARY KEY(AddressID, Person, OrdinalNumber) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BPContactToAddress ( + RelationshipNumber NVARCHAR(12) NOT NULL, + BusinessPartnerCompany NVARCHAR(10) NOT NULL, + BusinessPartnerPerson NVARCHAR(10) NOT NULL, + ValidityEndDate DATE NOT NULL, + AddressID NVARCHAR(10) NOT NULL, + AddressNumber NVARCHAR(10), + AdditionalStreetPrefixName NVARCHAR(40), + AdditionalStreetSuffixName NVARCHAR(40), + AddressTimeZone NVARCHAR(6), + CareOfName NVARCHAR(40), + CityCode NVARCHAR(12), + CityName NVARCHAR(40), + CompanyPostalCode NVARCHAR(10), + Country NVARCHAR(3), + County NVARCHAR(40), + DeliveryServiceNumber NVARCHAR(10), + DeliveryServiceTypeCode NVARCHAR(4), + District NVARCHAR(40), + FormOfAddress NVARCHAR(4), + FullName NVARCHAR(80), + HomeCityName NVARCHAR(40), + HouseNumber NVARCHAR(10), + HouseNumberSupplementText NVARCHAR(10), + Language NVARCHAR(2), + POBox NVARCHAR(10), + POBoxDeviatingCityName NVARCHAR(40), + POBoxDeviatingCountry NVARCHAR(3), + POBoxDeviatingRegion NVARCHAR(3), + POBoxIsWithoutNumber BOOLEAN, + POBoxLobbyName NVARCHAR(40), + POBoxPostalCode NVARCHAR(10), + Person NVARCHAR(10), + PostalCode NVARCHAR(10), + PrfrdCommMediumType NVARCHAR(3), + Region NVARCHAR(3), + StreetName NVARCHAR(60), + StreetPrefixName NVARCHAR(40), + StreetSuffixName NVARCHAR(40), + TaxJurisdiction NVARCHAR(15), + TransportZone NVARCHAR(10), + PRIMARY KEY(RelationshipNumber, BusinessPartnerCompany, BusinessPartnerPerson, ValidityEndDate, AddressID) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BPContactToFuncAndDept ( + RelationshipNumber NVARCHAR(12) NOT NULL, + BusinessPartnerCompany NVARCHAR(10) NOT NULL, + BusinessPartnerPerson NVARCHAR(10) NOT NULL, + ValidityEndDate DATE NOT NULL, + ContactPersonFunction NVARCHAR(4), + ContactPersonDepartment NVARCHAR(4), + PhoneNumber NVARCHAR(30), + PhoneNumberExtension NVARCHAR(10), + FaxNumber NVARCHAR(30), + FaxNumberExtension NVARCHAR(10), + EmailAddress NVARCHAR(241), + RelationshipCategory NVARCHAR(6), + PRIMARY KEY(RelationshipNumber, BusinessPartnerCompany, BusinessPartnerPerson, ValidityEndDate) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BuPaAddressUsage ( + BusinessPartner NVARCHAR(10) NOT NULL, + ValidityEndDate TIMESTAMP(0) NOT NULL, + AddressUsage NVARCHAR(10) NOT NULL, + AddressID NVARCHAR(10) NOT NULL, + ValidityStartDate TIMESTAMP(0), + StandardUsage BOOLEAN, + AuthorizationGroup NVARCHAR(4), + PRIMARY KEY(BusinessPartner, ValidityEndDate, AddressUsage, AddressID) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BuPaIdentification ( + BusinessPartner NVARCHAR(10) NOT NULL, + BPIdentificationType NVARCHAR(6) NOT NULL, + BPIdentificationNumber NVARCHAR(60) NOT NULL, + BPIdnNmbrIssuingInstitute NVARCHAR(40), + BPIdentificationEntryDate DATE, + Country NVARCHAR(3), + Region NVARCHAR(3), + ValidityStartDate DATE, + ValidityEndDate DATE, + AuthorizationGroup NVARCHAR(4), + PRIMARY KEY(BusinessPartner, BPIdentificationType, BPIdentificationNumber) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BuPaIndustry ( + IndustrySector NVARCHAR(10) NOT NULL, + IndustrySystemType NVARCHAR(4) NOT NULL, + BusinessPartner NVARCHAR(10) NOT NULL, + IsStandardIndustry NVARCHAR(1), + IndustryKeyDescription NVARCHAR(100), + PRIMARY KEY(IndustrySector, IndustrySystemType, BusinessPartner) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BusinessPartner ( + BusinessPartner NVARCHAR(10) NOT NULL, + Customer NVARCHAR(10), + Supplier NVARCHAR(10), + AcademicTitle NVARCHAR(4), + AuthorizationGroup NVARCHAR(4), + BusinessPartnerCategory NVARCHAR(1), + BusinessPartnerFullName NVARCHAR(81), + BusinessPartnerGrouping NVARCHAR(4), + BusinessPartnerName NVARCHAR(81), + BusinessPartnerUUID NVARCHAR(36), + CorrespondenceLanguage NVARCHAR(2), + CreatedByUser NVARCHAR(12), + CreationDate DATE, + CreationTime TIME, + FirstName NVARCHAR(40), + FormOfAddress NVARCHAR(4), + Industry NVARCHAR(10), + InternationalLocationNumber1 NVARCHAR(7), + InternationalLocationNumber2 NVARCHAR(5), + IsFemale BOOLEAN, + IsMale BOOLEAN, + IsNaturalPerson NVARCHAR(1), + IsSexUnknown BOOLEAN, + GenderCodeName NVARCHAR(1), + Language NVARCHAR(2), + LastChangeDate DATE, + LastChangeTime TIME, + LastChangedByUser NVARCHAR(12), + LastName NVARCHAR(40), + LegalForm NVARCHAR(2), + OrganizationBPName1 NVARCHAR(40), + OrganizationBPName2 NVARCHAR(40), + OrganizationBPName3 NVARCHAR(40), + OrganizationBPName4 NVARCHAR(40), + OrganizationFoundationDate DATE, + OrganizationLiquidationDate DATE, + SearchTerm1 NVARCHAR(20), + SearchTerm2 NVARCHAR(20), + AdditionalLastName NVARCHAR(40), + BirthDate DATE, + BusinessPartnerBirthplaceName NVARCHAR(40), + BusinessPartnerIsBlocked BOOLEAN, + BusinessPartnerType NVARCHAR(4), + ETag NVARCHAR(26), + GroupBusinessPartnerName1 NVARCHAR(40), + GroupBusinessPartnerName2 NVARCHAR(40), + IndependentAddressID NVARCHAR(10), + InternationalLocationNumber3 NVARCHAR(1), + MiddleName NVARCHAR(40), + NameCountry NVARCHAR(3), + NameFormat NVARCHAR(2), + PersonFullName NVARCHAR(80), + PersonNumber NVARCHAR(10), + IsMarkedForArchiving BOOLEAN, + BusinessPartnerIDByExtSystem NVARCHAR(20), + TradingPartner NVARCHAR(6), + PRIMARY KEY(BusinessPartner) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BusinessPartnerAddress ( + BusinessPartner NVARCHAR(10) NOT NULL, + AddressID NVARCHAR(10) NOT NULL, + ValidityStartDate TIMESTAMP(0), + ValidityEndDate TIMESTAMP(0), + AuthorizationGroup NVARCHAR(4), + AddressUUID NVARCHAR(36), + AdditionalStreetPrefixName NVARCHAR(40), + AdditionalStreetSuffixName NVARCHAR(40), + AddressTimeZone NVARCHAR(6), + CareOfName NVARCHAR(40), + CityCode NVARCHAR(12), + CityName NVARCHAR(40), + CompanyPostalCode NVARCHAR(10), + Country NVARCHAR(3), + County NVARCHAR(40), + DeliveryServiceNumber NVARCHAR(10), + DeliveryServiceTypeCode NVARCHAR(4), + District NVARCHAR(40), + FormOfAddress NVARCHAR(4), + FullName NVARCHAR(80), + HomeCityName NVARCHAR(40), + HouseNumber NVARCHAR(10), + HouseNumberSupplementText NVARCHAR(10), + Language NVARCHAR(2), + POBox NVARCHAR(10), + POBoxDeviatingCityName NVARCHAR(40), + POBoxDeviatingCountry NVARCHAR(3), + POBoxDeviatingRegion NVARCHAR(3), + POBoxIsWithoutNumber BOOLEAN, + POBoxLobbyName NVARCHAR(40), + POBoxPostalCode NVARCHAR(10), + Person NVARCHAR(10), + PostalCode NVARCHAR(10), + PrfrdCommMediumType NVARCHAR(3), + Region NVARCHAR(3), + StreetName NVARCHAR(60), + StreetPrefixName NVARCHAR(40), + StreetSuffixName NVARCHAR(40), + TaxJurisdiction NVARCHAR(15), + TransportZone NVARCHAR(10), + AddressIDByExternalSystem NVARCHAR(20), + PRIMARY KEY(BusinessPartner, AddressID) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BusinessPartnerBank ( + BusinessPartner NVARCHAR(10) NOT NULL, + BankIdentification NVARCHAR(4) NOT NULL, + BankCountryKey NVARCHAR(3), + BankName NVARCHAR(60), + BankNumber NVARCHAR(15), + SWIFTCode NVARCHAR(11), + BankControlKey NVARCHAR(2), + BankAccountHolderName NVARCHAR(60), + BankAccountName NVARCHAR(40), + ValidityStartDate TIMESTAMP(0), + ValidityEndDate TIMESTAMP(0), + IBAN NVARCHAR(34), + IBANValidityStartDate DATE, + BankAccount NVARCHAR(18), + BankAccountReferenceText NVARCHAR(20), + CollectionAuthInd BOOLEAN, + CityName NVARCHAR(35), + AuthorizationGroup NVARCHAR(4), + PRIMARY KEY(BusinessPartner, BankIdentification) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BusinessPartnerContact ( + RelationshipNumber NVARCHAR(12) NOT NULL, + BusinessPartnerCompany NVARCHAR(10) NOT NULL, + BusinessPartnerPerson NVARCHAR(10) NOT NULL, + ValidityEndDate DATE NOT NULL, + ValidityStartDate DATE, + IsStandardRelationship BOOLEAN, + RelationshipCategory NVARCHAR(6), + PRIMARY KEY(RelationshipNumber, BusinessPartnerCompany, BusinessPartnerPerson, ValidityEndDate) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BusinessPartnerRole ( + BusinessPartner NVARCHAR(10) NOT NULL, + BusinessPartnerRole NVARCHAR(6) NOT NULL, + ValidFrom TIMESTAMP(0), + ValidTo TIMESTAMP(0), + AuthorizationGroup NVARCHAR(4), + PRIMARY KEY(BusinessPartner, BusinessPartnerRole) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BusinessPartnerTaxNumber ( + BusinessPartner NVARCHAR(10) NOT NULL, + BPTaxType NVARCHAR(4) NOT NULL, + BPTaxNumber NVARCHAR(20), + BPTaxLongNumber NVARCHAR(60), + AuthorizationGroup NVARCHAR(4), + PRIMARY KEY(BusinessPartner, BPTaxType) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_Customer ( + Customer NVARCHAR(10) NOT NULL, + AuthorizationGroup NVARCHAR(4), + BillingIsBlockedForCustomer NVARCHAR(2), + CreatedByUser NVARCHAR(12), + CreationDate DATE, + CustomerAccountGroup NVARCHAR(4), + CustomerClassification NVARCHAR(2), + CustomerFullName NVARCHAR(220), + CustomerName NVARCHAR(80), + DeliveryIsBlocked NVARCHAR(2), + NFPartnerIsNaturalPerson NVARCHAR(1), + OrderIsBlockedForCustomer NVARCHAR(2), + PostingIsBlocked BOOLEAN, + Supplier NVARCHAR(10), + CustomerCorporateGroup NVARCHAR(10), + FiscalAddress NVARCHAR(10), + Industry NVARCHAR(4), + IndustryCode1 NVARCHAR(10), + IndustryCode2 NVARCHAR(10), + IndustryCode3 NVARCHAR(10), + IndustryCode4 NVARCHAR(10), + IndustryCode5 NVARCHAR(10), + InternationalLocationNumber1 NVARCHAR(7), + NielsenRegion NVARCHAR(2), + ResponsibleType NVARCHAR(2), + TaxNumber1 NVARCHAR(16), + TaxNumber2 NVARCHAR(11), + TaxNumber3 NVARCHAR(18), + TaxNumber4 NVARCHAR(18), + TaxNumber5 NVARCHAR(60), + TaxNumberType NVARCHAR(2), + VATRegistration NVARCHAR(20), + DeletionIndicator BOOLEAN, + PRIMARY KEY(Customer) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_CustomerCompany ( + Customer NVARCHAR(10) NOT NULL, + CompanyCode NVARCHAR(4) NOT NULL, + APARToleranceGroup NVARCHAR(4), + AccountByCustomer NVARCHAR(12), + AccountingClerk NVARCHAR(2), + AccountingClerkFaxNumber NVARCHAR(31), + AccountingClerkInternetAddress NVARCHAR(130), + AccountingClerkPhoneNumber NVARCHAR(30), + AlternativePayerAccount NVARCHAR(10), + AuthorizationGroup NVARCHAR(4), + CollectiveInvoiceVariant NVARCHAR(1), + CustomerAccountNote NVARCHAR(30), + CustomerHeadOffice NVARCHAR(10), + CustomerSupplierClearingIsUsed BOOLEAN, + HouseBank NVARCHAR(5), + InterestCalculationCode NVARCHAR(2), + InterestCalculationDate DATE, + IsToBeLocallyProcessed BOOLEAN, + ItemIsToBePaidSeparately BOOLEAN, + LayoutSortingRule NVARCHAR(3), + PaymentBlockingReason NVARCHAR(1), + PaymentMethodsList NVARCHAR(10), + PaymentTerms NVARCHAR(4), + PaytAdviceIsSentbyEDI BOOLEAN, + PhysicalInventoryBlockInd BOOLEAN, + ReconciliationAccount NVARCHAR(10), + RecordPaymentHistoryIndicator BOOLEAN, + UserAtCustomer NVARCHAR(15), + DeletionIndicator BOOLEAN, + CashPlanningGroup NVARCHAR(10), + KnownOrNegotiatedLeave NVARCHAR(4), + ValueAdjustmentKey NVARCHAR(2), + CustomerAccountGroup NVARCHAR(4), + PRIMARY KEY(Customer, CompanyCode) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_CustomerDunning ( + Customer NVARCHAR(10) NOT NULL, + CompanyCode NVARCHAR(4) NOT NULL, + DunningArea NVARCHAR(2) NOT NULL, + DunningBlock NVARCHAR(1), + DunningLevel NVARCHAR(1), + DunningProcedure NVARCHAR(4), + DunningRecipient NVARCHAR(10), + LastDunnedOn DATE, + LegDunningProcedureOn DATE, + DunningClerk NVARCHAR(2), + AuthorizationGroup NVARCHAR(4), + CustomerAccountGroup NVARCHAR(4), + PRIMARY KEY(Customer, CompanyCode, DunningArea) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_CustomerSalesArea ( + Customer NVARCHAR(10) NOT NULL, + SalesOrganization NVARCHAR(4) NOT NULL, + DistributionChannel NVARCHAR(2) NOT NULL, + Division NVARCHAR(2) NOT NULL, + AccountByCustomer NVARCHAR(12), + AuthorizationGroup NVARCHAR(4), + BillingIsBlockedForCustomer NVARCHAR(2), + CompleteDeliveryIsDefined BOOLEAN, + Currency NVARCHAR(5), + CustomerABCClassification NVARCHAR(2), + CustomerAccountAssignmentGroup NVARCHAR(2), + CustomerGroup NVARCHAR(2), + CustomerPaymentTerms NVARCHAR(4), + CustomerPriceGroup NVARCHAR(2), + CustomerPricingProcedure NVARCHAR(2), + DeliveryIsBlockedForCustomer NVARCHAR(2), + DeliveryPriority NVARCHAR(2), + IncotermsClassification NVARCHAR(3), + IncotermsLocation2 NVARCHAR(70), + IncotermsVersion NVARCHAR(4), + IncotermsLocation1 NVARCHAR(70), + DeletionIndicator BOOLEAN, + IncotermsTransferLocation NVARCHAR(28), + InvoiceDate NVARCHAR(2), + ItemOrderProbabilityInPercent NVARCHAR(3), + OrderCombinationIsAllowed BOOLEAN, + OrderIsBlockedForCustomer NVARCHAR(2), + PartialDeliveryIsAllowed NVARCHAR(1), + PriceListType NVARCHAR(2), + SalesGroup NVARCHAR(3), + SalesOffice NVARCHAR(4), + ShippingCondition NVARCHAR(2), + SupplyingPlant NVARCHAR(4), + SalesDistrict NVARCHAR(6), + InvoiceListSchedule NVARCHAR(2), + ExchangeRateType NVARCHAR(4), + AdditionalCustomerGroup1 NVARCHAR(3), + AdditionalCustomerGroup2 NVARCHAR(3), + AdditionalCustomerGroup3 NVARCHAR(3), + AdditionalCustomerGroup4 NVARCHAR(3), + AdditionalCustomerGroup5 NVARCHAR(3), + PaymentGuaranteeProcedure NVARCHAR(4), + CustomerAccountGroup NVARCHAR(4), + PRIMARY KEY(Customer, SalesOrganization, DistributionChannel, Division) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_CustomerSalesAreaTax ( + Customer NVARCHAR(10) NOT NULL, + SalesOrganization NVARCHAR(4) NOT NULL, + DistributionChannel NVARCHAR(2) NOT NULL, + Division NVARCHAR(2) NOT NULL, + DepartureCountry NVARCHAR(3) NOT NULL, + CustomerTaxCategory NVARCHAR(4) NOT NULL, + CustomerTaxClassification NVARCHAR(1), + PRIMARY KEY(Customer, SalesOrganization, DistributionChannel, Division, DepartureCountry, CustomerTaxCategory) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_CustomerWithHoldingTax ( + Customer NVARCHAR(10) NOT NULL, + CompanyCode NVARCHAR(4) NOT NULL, + WithholdingTaxType NVARCHAR(2) NOT NULL, + WithholdingTaxCode NVARCHAR(2), + WithholdingTaxAgent BOOLEAN, + ObligationDateBegin DATE, + ObligationDateEnd DATE, + WithholdingTaxNumber NVARCHAR(16), + WithholdingTaxCertificate NVARCHAR(25), + WithholdingTaxExmptPercent DECIMAL(5, 2), + ExemptionDateBegin DATE, + ExemptionDateEnd DATE, + ExemptionReason NVARCHAR(2), + AuthorizationGroup NVARCHAR(4), + PRIMARY KEY(Customer, CompanyCode, WithholdingTaxType) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_CustSalesPartnerFunc ( + Customer NVARCHAR(10) NOT NULL, + SalesOrganization NVARCHAR(4) NOT NULL, + DistributionChannel NVARCHAR(2) NOT NULL, + Division NVARCHAR(2) NOT NULL, + PartnerCounter NVARCHAR(3) NOT NULL, + PartnerFunction NVARCHAR(2) NOT NULL, + BPCustomerNumber NVARCHAR(10), + CustomerPartnerDescription NVARCHAR(30), + DefaultPartner BOOLEAN, + AuthorizationGroup NVARCHAR(4), + PRIMARY KEY(Customer, SalesOrganization, DistributionChannel, Division, PartnerCounter, PartnerFunction) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_Supplier ( + Supplier NVARCHAR(10) NOT NULL, + AlternativePayeeAccountNumber NVARCHAR(10), + AuthorizationGroup NVARCHAR(4), + CreatedByUser NVARCHAR(12), + CreationDate DATE, + Customer NVARCHAR(10), + PaymentIsBlockedForSupplier BOOLEAN, + PostingIsBlocked BOOLEAN, + PurchasingIsBlocked BOOLEAN, + SupplierAccountGroup NVARCHAR(4), + SupplierFullName NVARCHAR(220), + SupplierName NVARCHAR(80), + VATRegistration NVARCHAR(20), + BirthDate DATE, + ConcatenatedInternationalLocNo NVARCHAR(20), + DeletionIndicator BOOLEAN, + FiscalAddress NVARCHAR(10), + Industry NVARCHAR(4), + InternationalLocationNumber1 NVARCHAR(7), + InternationalLocationNumber2 NVARCHAR(5), + InternationalLocationNumber3 NVARCHAR(1), + IsNaturalPerson NVARCHAR(1), + ResponsibleType NVARCHAR(2), + SuplrQltyInProcmtCertfnValidTo DATE, + SuplrQualityManagementSystem NVARCHAR(4), + SupplierCorporateGroup NVARCHAR(10), + SupplierProcurementBlock NVARCHAR(2), + TaxNumber1 NVARCHAR(16), + TaxNumber2 NVARCHAR(11), + TaxNumber3 NVARCHAR(18), + TaxNumber4 NVARCHAR(18), + TaxNumber5 NVARCHAR(60), + TaxNumberResponsible NVARCHAR(18), + TaxNumberType NVARCHAR(2), + SuplrProofOfDelivRlvtCode NVARCHAR(1), + BR_TaxIsSplit BOOLEAN, + PRIMARY KEY(Supplier) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_SupplierCompany ( + Supplier NVARCHAR(10) NOT NULL, + CompanyCode NVARCHAR(4) NOT NULL, + AuthorizationGroup NVARCHAR(4), + CompanyCodeName NVARCHAR(25), + PaymentBlockingReason NVARCHAR(1), + SupplierIsBlockedForPosting BOOLEAN, + AccountingClerk NVARCHAR(2), + AccountingClerkFaxNumber NVARCHAR(31), + AccountingClerkPhoneNumber NVARCHAR(30), + SupplierClerk NVARCHAR(15), + SupplierClerkURL NVARCHAR(130), + PaymentMethodsList NVARCHAR(10), + PaymentTerms NVARCHAR(4), + ClearCustomerSupplier BOOLEAN, + IsToBeLocallyProcessed BOOLEAN, + ItemIsToBePaidSeparately BOOLEAN, + PaymentIsToBeSentByEDI BOOLEAN, + HouseBank NVARCHAR(5), + CheckPaidDurationInDays DECIMAL(3, 0), + Currency NVARCHAR(5), + BillOfExchLmtAmtInCoCodeCrcy DECIMAL(14, 3), + SupplierClerkIDBySupplier NVARCHAR(12), + ReconciliationAccount NVARCHAR(10), + InterestCalculationCode NVARCHAR(2), + InterestCalculationDate DATE, + SupplierHeadOffice NVARCHAR(10), + AlternativePayee NVARCHAR(10), + LayoutSortingRule NVARCHAR(3), + APARToleranceGroup NVARCHAR(4), + SupplierCertificationDate DATE, + SupplierAccountNote NVARCHAR(30), + WithholdingTaxCountry NVARCHAR(3), + DeletionIndicator BOOLEAN, + CashPlanningGroup NVARCHAR(10), + IsToBeCheckedForDuplicates BOOLEAN, + MinorityGroup NVARCHAR(3), + SupplierAccountGroup NVARCHAR(4), + PRIMARY KEY(Supplier, CompanyCode) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_SupplierDunning ( + Supplier NVARCHAR(10) NOT NULL, + CompanyCode NVARCHAR(4) NOT NULL, + DunningArea NVARCHAR(2) NOT NULL, + DunningBlock NVARCHAR(1), + DunningLevel NVARCHAR(1), + DunningProcedure NVARCHAR(4), + DunningRecipient NVARCHAR(10), + LastDunnedOn DATE, + LegDunningProcedureOn DATE, + DunningClerk NVARCHAR(2), + AuthorizationGroup NVARCHAR(4), + SupplierAccountGroup NVARCHAR(4), + PRIMARY KEY(Supplier, CompanyCode, DunningArea) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_SupplierPartnerFunc ( + Supplier NVARCHAR(10) NOT NULL, + PurchasingOrganization NVARCHAR(4) NOT NULL, + SupplierSubrange NVARCHAR(6) NOT NULL, + Plant NVARCHAR(4) NOT NULL, + PartnerFunction NVARCHAR(2) NOT NULL, + PartnerCounter NVARCHAR(3) NOT NULL, + DefaultPartner BOOLEAN, + CreationDate DATE, + CreatedByUser NVARCHAR(12), + ReferenceSupplier NVARCHAR(10), + AuthorizationGroup NVARCHAR(4), + PRIMARY KEY(Supplier, PurchasingOrganization, SupplierSubrange, Plant, PartnerFunction, PartnerCounter) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_SupplierPurchasingOrg ( + Supplier NVARCHAR(10) NOT NULL, + PurchasingOrganization NVARCHAR(4) NOT NULL, + CalculationSchemaGroupCode NVARCHAR(2), + DeletionIndicator BOOLEAN, + IncotermsClassification NVARCHAR(3), + IncotermsTransferLocation NVARCHAR(28), + IncotermsVersion NVARCHAR(4), + IncotermsLocation1 NVARCHAR(70), + IncotermsLocation2 NVARCHAR(70), + InvoiceIsGoodsReceiptBased BOOLEAN, + MaterialPlannedDeliveryDurn DECIMAL(3, 0), + MinimumOrderAmount DECIMAL(14, 3), + PaymentTerms NVARCHAR(4), + PricingDateControl NVARCHAR(1), + PurOrdAutoGenerationIsAllowed BOOLEAN, + PurchaseOrderCurrency NVARCHAR(5), + PurchasingGroup NVARCHAR(3), + PurchasingIsBlockedForSupplier BOOLEAN, + ShippingCondition NVARCHAR(2), + SupplierABCClassificationCode NVARCHAR(1), + SupplierPhoneNumber NVARCHAR(16), + SupplierRespSalesPersonName NVARCHAR(30), + AuthorizationGroup NVARCHAR(4), + SupplierAccountGroup NVARCHAR(4), + PRIMARY KEY(Supplier, PurchasingOrganization) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_SupplierWithHoldingTax ( + Supplier NVARCHAR(10) NOT NULL, + CompanyCode NVARCHAR(4) NOT NULL, + WithholdingTaxType NVARCHAR(2) NOT NULL, + ExemptionDateBegin DATE, + ExemptionDateEnd DATE, + ExemptionReason NVARCHAR(2), + IsWithholdingTaxSubject BOOLEAN, + RecipientType NVARCHAR(2), + WithholdingTaxCertificate NVARCHAR(25), + WithholdingTaxCode NVARCHAR(2), + WithholdingTaxExmptPercent DECIMAL(5, 2), + WithholdingTaxNumber NVARCHAR(16), + AuthorizationGroup NVARCHAR(4), + PRIMARY KEY(Supplier, CompanyCode, WithholdingTaxType) +); + +CREATE TABLE Statuses_texts ( + locale NVARCHAR(14) NOT NULL, + code NVARCHAR(255) NOT NULL, + text NVARCHAR(255), + PRIMARY KEY(locale, code) +); + +CREATE TABLE my_bookshop_Books_attachments ( + up__ID NVARCHAR(36) NOT NULL, + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + modifiedAt TIMESTAMP(7), + modifiedBy NVARCHAR(255), + content BINARY LARGE OBJECT, + mimeType NVARCHAR(255), + fileName NVARCHAR(255), + contentId NVARCHAR(255), + status NVARCHAR(255), + scannedAt TIMESTAMP(7), + note NVARCHAR(255), + folderId NVARCHAR(255), + repositoryId NVARCHAR(255), + objectId NVARCHAR(255), + PRIMARY KEY(up__ID, ID) +); + +CREATE TABLE my_bookshop_Books_texts ( + ID_texts NVARCHAR(36) NOT NULL, + locale NVARCHAR(14), + ID NVARCHAR(36), + title NVARCHAR(111), + descr NVARCHAR(1111), + PRIMARY KEY(ID_texts), + CONSTRAINT my_bookshop_Books_texts_locale UNIQUE (locale, ID) +); + +CREATE TABLE my_bookshop_Genres_texts ( + locale NVARCHAR(14) NOT NULL, + name NVARCHAR(255), + descr NVARCHAR(1000), + ID INTEGER NOT NULL, + PRIMARY KEY(locale, ID) +); + +CREATE TABLE my_bookshop_Orders_changes ( + up__ID NVARCHAR(36) NOT NULL, + change_ID NVARCHAR(36) NOT NULL, + PRIMARY KEY(up__ID, change_ID) +); + +CREATE TABLE sap_common_Languages_texts ( + locale NVARCHAR(14) NOT NULL, + name NVARCHAR(255), + descr NVARCHAR(1000), + code NVARCHAR(14) NOT NULL, + PRIMARY KEY(locale, code) +); + +CREATE TABLE sap_common_Currencies_texts ( + locale NVARCHAR(14) NOT NULL, + name NVARCHAR(255), + descr NVARCHAR(1000), + code NVARCHAR(3) NOT NULL, + PRIMARY KEY(locale, code) +); + +CREATE TABLE DRAFT_DraftAdministrativeData ( + DraftUUID NVARCHAR(36) NOT NULL, + CreationDateTime TIMESTAMP(7), + CreatedByUser NVARCHAR(256), + DraftIsCreatedByMe BOOLEAN, + LastChangeDateTime TIMESTAMP(7), + LastChangedByUser NVARCHAR(256), + InProcessByUser NVARCHAR(256), + DraftIsProcessedByMe BOOLEAN, + PRIMARY KEY(DraftUUID) +); + +CREATE TABLE AdminService_Books_drafts ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7) NULL, + createdBy NVARCHAR(255) NULL, + modifiedAt TIMESTAMP(7) NULL, + modifiedBy NVARCHAR(255) NULL, + title NVARCHAR(111) NULL, + descr NVARCHAR(1111) NULL, + author_ID NVARCHAR(36) NULL, + genre_ID INTEGER NULL, + stock INTEGER NULL, + price DECIMAL(9, 2) NULL, + currency_code NVARCHAR(3) NULL, + rating DECIMAL(2, 1) NULL, + isReviewable BOOLEAN NULL DEFAULT TRUE, + isbn NVARCHAR(40) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID) +); + +CREATE TABLE AdminService_Books_attachments_drafts ( + up__ID NVARCHAR(36) NOT NULL, + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7) NULL, + createdBy NVARCHAR(255) NULL, + modifiedAt TIMESTAMP(7) NULL, + modifiedBy NVARCHAR(255) NULL, + content BINARY LARGE OBJECT NULL, + mimeType NVARCHAR(255) NULL, + fileName NVARCHAR(255) NULL, + contentId NVARCHAR(255) NULL, + status NVARCHAR(255) NULL, + scannedAt TIMESTAMP(7) NULL, + note NVARCHAR(255) NULL, + folderId NVARCHAR(255) NULL, + repositoryId NVARCHAR(255) NULL, + objectId NVARCHAR(255) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(up__ID, ID) +); + +CREATE TABLE AdminService_Books_texts_drafts ( + ID_texts NVARCHAR(36) NOT NULL, + locale NVARCHAR(14) NULL, + ID NVARCHAR(36) NULL, + title NVARCHAR(111) NULL, + descr NVARCHAR(1111) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID_texts) +); + +CREATE TABLE AdminService_Orders_drafts ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7) NULL, + createdBy NVARCHAR(255) NULL, + modifiedAt TIMESTAMP(7) NULL, + modifiedBy NVARCHAR(255) NULL, + OrderNo NVARCHAR(255) NULL, + buyer NVARCHAR(255) NULL, + total DECIMAL(9, 2) NULL, + currency_code NVARCHAR(3) NULL, + shippingAddress_ID NVARCHAR(10) NULL, + shippingAddress_businessPartner NVARCHAR(10) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID) +); + +CREATE TABLE AdminService_OrderItems_drafts ( + ID NVARCHAR(36) NOT NULL, + parent_ID NVARCHAR(36) NULL, + book_ID NVARCHAR(36) NULL, + quantity INTEGER NULL, + amount DECIMAL(9, 2) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID) +); + +CREATE TABLE NotesService_Notes_drafts ( + ID NVARCHAR(36) NOT NULL, + note NVARCHAR(255) NULL, + address_ID NVARCHAR(10) NULL, + address_businessPartner NVARCHAR(10) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID) +); + +CREATE TABLE ReviewService_Reviews_drafts ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7) NULL, + createdBy NVARCHAR(255) NULL, + modifiedAt TIMESTAMP(7) NULL, + modifiedBy NVARCHAR(255) NULL, + book_ID NVARCHAR(36) NULL, + rating INTEGER NULL, + title NVARCHAR(111) NULL, + text NVARCHAR(1111) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID) +); + +CREATE VIEW AdminService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.createdBy, + Books_0.modifiedAt, + Books_0.modifiedBy, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM my_bookshop_Books AS Books_0; + +CREATE VIEW AdminService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM my_bookshop_Authors AS Authors_0; + +CREATE VIEW AdminService_Orders AS SELECT + Orders_0.ID, + Orders_0.createdAt, + Orders_0.createdBy, + Orders_0.modifiedAt, + Orders_0.modifiedBy, + Orders_0.OrderNo, + Orders_0.buyer, + Orders_0.total, + Orders_0.currency_code, + Orders_0.shippingAddress_ID, + Orders_0.shippingAddress_businessPartner +FROM my_bookshop_Orders AS Orders_0; + +CREATE VIEW AdminService_Languages AS SELECT + CommonLanguages_0.name, + CommonLanguages_0.descr, + CommonLanguages_0.code +FROM sap_common_Languages AS CommonLanguages_0; + +CREATE VIEW CatalogService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.modifiedAt, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM my_bookshop_Books AS Books_0; + +CREATE VIEW CatalogService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM my_bookshop_Authors AS Authors_0; + +CREATE VIEW CatalogService_Reviews AS SELECT + Reviews_0.ID, + Reviews_0.createdAt, + Reviews_0.createdBy, + Reviews_0.modifiedAt, + Reviews_0.modifiedBy, + Reviews_0.book_ID, + Reviews_0.rating, + Reviews_0.title, + Reviews_0.text +FROM my_bookshop_Reviews AS Reviews_0; + +CREATE VIEW my_bookshop_NoteableAddresses AS SELECT + A_BusinessPartnerAddress_0.AddressID AS ID, + A_BusinessPartnerAddress_0.BusinessPartner AS businessPartner, + A_BusinessPartnerAddress_0.Country AS country, + A_BusinessPartnerAddress_0.CityName AS city, + A_BusinessPartnerAddress_0.PostalCode AS postalCode, + A_BusinessPartnerAddress_0.StreetName AS street, + A_BusinessPartnerAddress_0.HouseNumber AS houseNumber +FROM API_BUSINESS_PARTNER_A_BusinessPartnerAddress AS A_BusinessPartnerAddress_0; + +CREATE VIEW NotesService_Notes AS SELECT + Notes_0.ID, + Notes_0.note, + Notes_0.address_ID, + Notes_0.address_businessPartner +FROM my_bookshop_Notes AS Notes_0; + +CREATE VIEW ReviewService_Reviews AS SELECT + Reviews_0.ID, + Reviews_0.createdAt, + Reviews_0.createdBy, + Reviews_0.modifiedAt, + Reviews_0.modifiedBy, + Reviews_0.book_ID, + Reviews_0.rating, + Reviews_0.title, + Reviews_0.text +FROM my_bookshop_Reviews AS Reviews_0; + +CREATE VIEW ReviewService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.modifiedAt, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM my_bookshop_Books AS Books_0; + +CREATE VIEW ReviewService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM my_bookshop_Authors AS Authors_0; + +CREATE VIEW AdminService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM my_bookshop_Genres AS Genres_0; + +CREATE VIEW AdminService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM sap_common_Currencies AS Currencies_0; + +CREATE VIEW AdminService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW AdminService_Books_texts AS SELECT + texts_0.ID_texts, + texts_0.locale, + texts_0.ID, + texts_0.title, + texts_0.descr +FROM my_bookshop_Books_texts AS texts_0; + +CREATE VIEW AdminService_OrderItems AS SELECT + OrderItems_0.ID, + OrderItems_0.parent_ID, + OrderItems_0.book_ID, + OrderItems_0.quantity, + OrderItems_0.amount +FROM my_bookshop_OrderItems AS OrderItems_0; + +CREATE VIEW AdminService_Orders_changes AS SELECT + changes_0.up__ID, + changes_0.change_ID +FROM my_bookshop_Orders_changes AS changes_0; + +CREATE VIEW AdminService_Addresses AS SELECT + Addresses_0.ID, + Addresses_0.businessPartner, + Addresses_0.country, + Addresses_0.city, + Addresses_0.postalCode, + Addresses_0.street, + Addresses_0.houseNumber, + Addresses_0.tombstone +FROM my_bookshop_Addresses AS Addresses_0; + +CREATE VIEW AdminService_Languages_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.code +FROM sap_common_Languages_texts AS texts_0; + +CREATE VIEW CatalogService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM my_bookshop_Genres AS Genres_0; + +CREATE VIEW CatalogService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM sap_common_Currencies AS Currencies_0; + +CREATE VIEW CatalogService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW CatalogService_Books_texts AS SELECT + texts_0.ID_texts, + texts_0.locale, + texts_0.ID, + texts_0.title, + texts_0.descr +FROM my_bookshop_Books_texts AS texts_0; + +CREATE VIEW ReviewService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM my_bookshop_Genres AS Genres_0; + +CREATE VIEW ReviewService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM sap_common_Currencies AS Currencies_0; + +CREATE VIEW ReviewService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW ReviewService_Books_texts AS SELECT + texts_0.ID_texts, + texts_0.locale, + texts_0.ID, + texts_0.title, + texts_0.descr +FROM my_bookshop_Books_texts AS texts_0; + +CREATE VIEW AdminService_Genres_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.ID +FROM my_bookshop_Genres_texts AS texts_0; + +CREATE VIEW AdminService_Currencies_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.code +FROM sap_common_Currencies_texts AS texts_0; + +CREATE VIEW AdminService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM Statuses AS Statuses_0; + +CREATE VIEW AdminService_Changes AS SELECT + Changes_0.ID, + Changes_0.createdAt, + Changes_0.createdBy, + Changes_0.changeLogID, + Changes_0.rootEntity, + Changes_0.rootIdentifier, + Changes_0.attribute, + Changes_0.valueChangedFrom, + Changes_0.valueChangedTo, + Changes_0.valueDataType, + Changes_0.targetIdentifier, + Changes_0.targetEntity, + Changes_0.path, + Changes_0.modification +FROM sap_changelog_Changes AS Changes_0; + +CREATE VIEW CatalogService_Genres_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.ID +FROM my_bookshop_Genres_texts AS texts_0; + +CREATE VIEW CatalogService_Currencies_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.code +FROM sap_common_Currencies_texts AS texts_0; + +CREATE VIEW CatalogService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM Statuses AS Statuses_0; + +CREATE VIEW ReviewService_Genres_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.ID +FROM my_bookshop_Genres_texts AS texts_0; + +CREATE VIEW ReviewService_Currencies_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.code +FROM sap_common_Currencies_texts AS texts_0; + +CREATE VIEW ReviewService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM Statuses AS Statuses_0; + +CREATE VIEW AdminService_Statuses_texts AS SELECT + texts_0.locale, + texts_0.code, + texts_0.text +FROM Statuses_texts AS texts_0; + +CREATE VIEW CatalogService_Statuses_texts AS SELECT + texts_0.locale, + texts_0.code, + texts_0.text +FROM Statuses_texts AS texts_0; + +CREATE VIEW ReviewService_Statuses_texts AS SELECT + texts_0.locale, + texts_0.code, + texts_0.text +FROM Statuses_texts AS texts_0; + +CREATE VIEW localized_Statuses AS SELECT + L_0.code, + coalesce(localized_1.text, L_0.text) AS text +FROM (Statuses AS L_0 LEFT JOIN Statuses_texts AS localized_1 ON localized_1.code = L_0.code AND localized_1.locale = @locale); + +CREATE VIEW localized_my_bookshop_Books AS SELECT + L_0.ID, + L_0.createdAt, + L_0.createdBy, + L_0.modifiedAt, + L_0.modifiedBy, + coalesce(localized_1.title, L_0.title) AS title, + coalesce(localized_1.descr, L_0.descr) AS descr, + L_0.author_ID, + L_0.genre_ID, + L_0.stock, + L_0.price, + L_0.currency_code, + L_0.rating, + L_0.isReviewable, + L_0.isbn +FROM (my_bookshop_Books AS L_0 LEFT JOIN my_bookshop_Books_texts AS localized_1 ON localized_1.ID = L_0.ID AND localized_1.locale = @locale); + +CREATE VIEW localized_my_bookshop_Genres AS SELECT + coalesce(localized_1.name, L_0.name) AS name, + coalesce(localized_1.descr, L_0.descr) AS descr, + L_0.ID, + L_0.parent_ID +FROM (my_bookshop_Genres AS L_0 LEFT JOIN my_bookshop_Genres_texts AS localized_1 ON localized_1.ID = L_0.ID AND localized_1.locale = @locale); + +CREATE VIEW localized_sap_common_Languages AS SELECT + coalesce(localized_1.name, L_0.name) AS name, + coalesce(localized_1.descr, L_0.descr) AS descr, + L_0.code +FROM (sap_common_Languages AS L_0 LEFT JOIN sap_common_Languages_texts AS localized_1 ON localized_1.code = L_0.code AND localized_1.locale = @locale); + +CREATE VIEW localized_sap_common_Currencies AS SELECT + coalesce(localized_1.name, L_0.name) AS name, + coalesce(localized_1.descr, L_0.descr) AS descr, + L_0.code, + L_0.symbol, + L_0.minorUnit +FROM (sap_common_Currencies AS L_0 LEFT JOIN sap_common_Currencies_texts AS localized_1 ON localized_1.code = L_0.code AND localized_1.locale = @locale); + +CREATE VIEW localized_my_bookshop_Authors AS SELECT + L.ID, + L.createdAt, + L.createdBy, + L.modifiedAt, + L.modifiedBy, + L.name, + L.dateOfBirth, + L.dateOfDeath, + L.placeOfBirth, + L.placeOfDeath +FROM my_bookshop_Authors AS L; + +CREATE VIEW localized_my_bookshop_Orders AS SELECT + L.ID, + L.createdAt, + L.createdBy, + L.modifiedAt, + L.modifiedBy, + L.OrderNo, + L.buyer, + L.total, + L.currency_code, + L.shippingAddress_ID, + L.shippingAddress_businessPartner +FROM my_bookshop_Orders AS L; + +CREATE VIEW localized_my_bookshop_OrderItems AS SELECT + L.ID, + L.parent_ID, + L.book_ID, + L.quantity, + L.amount +FROM my_bookshop_OrderItems AS L; + +CREATE VIEW localized_my_bookshop_Reviews AS SELECT + L.ID, + L.createdAt, + L.createdBy, + L.modifiedAt, + L.modifiedBy, + L.book_ID, + L.rating, + L.title, + L.text +FROM my_bookshop_Reviews AS L; + +CREATE VIEW localized_my_bookshop_Books_attachments AS SELECT + L.up__ID, + L.ID, + L.createdAt, + L.createdBy, + L.modifiedAt, + L.modifiedBy, + L.content, + L.mimeType, + L.fileName, + L.contentId, + L.status, + L.scannedAt, + L.note, + L.folderId, + L.repositoryId, + L.objectId +FROM my_bookshop_Books_attachments AS L; + +CREATE VIEW localized_my_bookshop_Orders_changes AS SELECT + L.up__ID, + L.change_ID +FROM my_bookshop_Orders_changes AS L; + +CREATE VIEW AdminService_DraftAdministrativeData AS SELECT + DraftAdministrativeData.DraftUUID, + DraftAdministrativeData.CreationDateTime, + DraftAdministrativeData.CreatedByUser, + DraftAdministrativeData.DraftIsCreatedByMe, + DraftAdministrativeData.LastChangeDateTime, + DraftAdministrativeData.LastChangedByUser, + DraftAdministrativeData.InProcessByUser, + DraftAdministrativeData.DraftIsProcessedByMe +FROM DRAFT_DraftAdministrativeData AS DraftAdministrativeData; + +CREATE VIEW NotesService_DraftAdministrativeData AS SELECT + DraftAdministrativeData.DraftUUID, + DraftAdministrativeData.CreationDateTime, + DraftAdministrativeData.CreatedByUser, + DraftAdministrativeData.DraftIsCreatedByMe, + DraftAdministrativeData.LastChangeDateTime, + DraftAdministrativeData.LastChangedByUser, + DraftAdministrativeData.InProcessByUser, + DraftAdministrativeData.DraftIsProcessedByMe +FROM DRAFT_DraftAdministrativeData AS DraftAdministrativeData; + +CREATE VIEW ReviewService_DraftAdministrativeData AS SELECT + DraftAdministrativeData.DraftUUID, + DraftAdministrativeData.CreationDateTime, + DraftAdministrativeData.CreatedByUser, + DraftAdministrativeData.DraftIsCreatedByMe, + DraftAdministrativeData.LastChangeDateTime, + DraftAdministrativeData.LastChangedByUser, + DraftAdministrativeData.InProcessByUser, + DraftAdministrativeData.DraftIsProcessedByMe +FROM DRAFT_DraftAdministrativeData AS DraftAdministrativeData; + +CREATE VIEW NotesService_Addresses AS SELECT + NoteableAddresses_0.ID, + NoteableAddresses_0.businessPartner, + NoteableAddresses_0.country, + NoteableAddresses_0.city, + NoteableAddresses_0.postalCode, + NoteableAddresses_0.street, + NoteableAddresses_0.houseNumber +FROM my_bookshop_NoteableAddresses AS NoteableAddresses_0; + +CREATE VIEW localized_AdminService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.createdBy, + Books_0.modifiedAt, + Books_0.modifiedBy, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM localized_my_bookshop_Books AS Books_0; + +CREATE VIEW localized_AdminService_Languages AS SELECT + CommonLanguages_0.name, + CommonLanguages_0.descr, + CommonLanguages_0.code +FROM localized_sap_common_Languages AS CommonLanguages_0; + +CREATE VIEW localized_CatalogService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.modifiedAt, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM localized_my_bookshop_Books AS Books_0; + +CREATE VIEW localized_ReviewService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.modifiedAt, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM localized_my_bookshop_Books AS Books_0; + +CREATE VIEW localized_AdminService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM localized_my_bookshop_Genres AS Genres_0; + +CREATE VIEW localized_AdminService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM localized_sap_common_Currencies AS Currencies_0; + +CREATE VIEW localized_CatalogService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM localized_my_bookshop_Genres AS Genres_0; + +CREATE VIEW localized_CatalogService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM localized_sap_common_Currencies AS Currencies_0; + +CREATE VIEW localized_ReviewService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM localized_my_bookshop_Genres AS Genres_0; + +CREATE VIEW localized_ReviewService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM localized_sap_common_Currencies AS Currencies_0; + +CREATE VIEW localized_AdminService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM localized_Statuses AS Statuses_0; + +CREATE VIEW localized_CatalogService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM localized_Statuses AS Statuses_0; + +CREATE VIEW localized_ReviewService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM localized_Statuses AS Statuses_0; + +CREATE VIEW localized_AdminService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM localized_my_bookshop_Authors AS Authors_0; + +CREATE VIEW localized_AdminService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM localized_my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW localized_AdminService_OrderItems AS SELECT + OrderItems_0.ID, + OrderItems_0.parent_ID, + OrderItems_0.book_ID, + OrderItems_0.quantity, + OrderItems_0.amount +FROM localized_my_bookshop_OrderItems AS OrderItems_0; + +CREATE VIEW localized_CatalogService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM localized_my_bookshop_Authors AS Authors_0; + +CREATE VIEW localized_CatalogService_Reviews AS SELECT + Reviews_0.ID, + Reviews_0.createdAt, + Reviews_0.createdBy, + Reviews_0.modifiedAt, + Reviews_0.modifiedBy, + Reviews_0.book_ID, + Reviews_0.rating, + Reviews_0.title, + Reviews_0.text +FROM localized_my_bookshop_Reviews AS Reviews_0; + +CREATE VIEW localized_CatalogService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM localized_my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW localized_ReviewService_Reviews AS SELECT + Reviews_0.ID, + Reviews_0.createdAt, + Reviews_0.createdBy, + Reviews_0.modifiedAt, + Reviews_0.modifiedBy, + Reviews_0.book_ID, + Reviews_0.rating, + Reviews_0.title, + Reviews_0.text +FROM localized_my_bookshop_Reviews AS Reviews_0; + +CREATE VIEW localized_ReviewService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM localized_my_bookshop_Authors AS Authors_0; + +CREATE VIEW localized_ReviewService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM localized_my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW localized_AdminService_Orders AS SELECT + Orders_0.ID, + Orders_0.createdAt, + Orders_0.createdBy, + Orders_0.modifiedAt, + Orders_0.modifiedBy, + Orders_0.OrderNo, + Orders_0.buyer, + Orders_0.total, + Orders_0.currency_code, + Orders_0.shippingAddress_ID, + Orders_0.shippingAddress_businessPartner +FROM localized_my_bookshop_Orders AS Orders_0; + +CREATE VIEW localized_AdminService_Orders_changes AS SELECT + changes_0.up__ID, + changes_0.change_ID +FROM localized_my_bookshop_Orders_changes AS changes_0; + diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/swagger/index.html b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/swagger/index.html new file mode 100644 index 000000000..c1f761271 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/main/resources/swagger/index.html @@ -0,0 +1,93 @@ + + + + + + Swagger UI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddressITestBase.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddressITestBase.java new file mode 100644 index 000000000..ed718019d --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddressITestBase.java @@ -0,0 +1,114 @@ +package my.bookshop; + +import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.HttpHeaders; +import org.springframework.test.web.reactive.server.WebTestClient; + +import com.sap.cds.services.changeset.ChangeSetListener; + +import cds.gen.adminservice.Orders; +import cds.gen.api_business_partner.ABusinessPartnerAddress; +import cds.gen.api_business_partner.ApiBusinessPartner; +import cds.gen.api_business_partner.ApiBusinessPartner_; +import cds.gen.api_business_partner.BusinessPartnerChangedContext; + +public class AdminServiceAddressITestBase { + + private static final String ordersURI = "/api/admin/Orders"; + private static final String orderURI = ordersURI + "(IsActiveEntity=true,ID=%s)"; + private static final String addressesURI = "/api/admin/Addresses"; + private static final String remoteAddressURI = "/api/API_BUSINESS_PARTNER/A_BusinessPartnerAddress(BusinessPartner='%s',AddressID='%s')"; + + @Autowired + private WebTestClient client; + + @Autowired + @Qualifier(ApiBusinessPartner_.CDS_NAME) + private ApiBusinessPartner bupa; + + public void testAddressesValueHelp() { + client.get().uri(addressesURI).headers(this::adminCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.['@context']").isEqualTo("$metadata#Addresses") + .jsonPath("$.value[0].ID").isEqualTo("100") + .jsonPath("$.value[0].businessPartner").isEqualTo("10401010") + .jsonPath("$.value[1].ID").isEqualTo("200") + .jsonPath("$.value[1].businessPartner").isEqualTo("10401010") + .jsonPath("$.value[2].ID").isEqualTo("300") + .jsonPath("$.value[2].businessPartner").isEqualTo("10401010"); + } + + public void testOrderWithAddress() throws InterruptedException { + Orders order = Orders.create(); + order.setOrderNo("1337"); + order.setShippingAddressId("100"); + + String id = UUID.randomUUID().toString(); + client.put().uri(String.format(orderURI, id)) + .headers(this::adminCredentials) + .header("Content-Type", "application/json") + .bodyValue(order.toJson()) + .exchange() + .expectStatus().isCreated(); + + client.get().uri(String.format(orderURI, id) + "?$expand=shippingAddress").headers(this::adminCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.ID").isEqualTo(id) + .jsonPath("$.OrderNo").isEqualTo(order.getOrderNo()) + .jsonPath("$.shippingAddress.ID").isEqualTo("100") + .jsonPath("$.shippingAddress.businessPartner").isEqualTo("10401010") + .jsonPath("$.shippingAddress.houseNumber").isEqualTo("16"); + + client.get().uri(String.format(orderURI, id) + "/shippingAddress").headers(this::adminCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.ID").isEqualTo("100") + .jsonPath("$.businessPartner").isEqualTo("10401010") + .jsonPath("$.houseNumber").isEqualTo("16"); + + // react on remote address update + CountDownLatch latch = new CountDownLatch(1); + bupa.on(BusinessPartnerChangedContext.CDS_NAME, null, (context) -> context.getChangeSetContext().register(new ChangeSetListener(){ + + @Override + public void afterClose(boolean completed) { + latch.countDown(); + } + + })); + + // update remote address + ABusinessPartnerAddress address = ABusinessPartnerAddress.create(); + address.setHouseNumber("17"); + + client.patch().uri(String.format(remoteAddressURI, "10401010", "100")).headers(this::authenticatedCredentials) + .header("Content-Type", "application/json") + .bodyValue(address.toJson()) + .exchange() + .expectStatus().isOk(); + + // wait for remote address update + latch.await(30, TimeUnit.SECONDS); + client.get().uri(String.format(orderURI, id) + "/shippingAddress").headers(this::adminCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.ID").isEqualTo("100") + .jsonPath("$.businessPartner").isEqualTo("10401010") + .jsonPath("$.houseNumber").isEqualTo("17"); + } + + private void adminCredentials(HttpHeaders headers) { + headers.setBasicAuth("admin", "admin"); + } + + private void authenticatedCredentials(HttpHeaders headers) { + headers.setBasicAuth("authenticated", ""); + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddress_default_ITest.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddress_default_ITest.java new file mode 100644 index 000000000..42b094538 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddress_default_ITest.java @@ -0,0 +1,29 @@ +package my.bookshop; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.test.context.ActiveProfiles; + +/** + * Runs tests defined in {@link AdminServiceAddressITestBase} with the default profile. + * The default profile doesn't create any remote services, so the application behaves as if + * the AdminService and the API_BUSINESS_PARTNER service were provided by the same application. + */ +@ActiveProfiles("default") +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +public class AdminServiceAddress_default_ITest extends AdminServiceAddressITestBase { + + @Test + @Override + public void testAddressesValueHelp() { + super.testAddressesValueHelp(); + } + + @Test + @Override + public void testOrderWithAddress() throws InterruptedException { + super.testOrderWithAddress(); + } + +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddress_mocked_ITest.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddress_mocked_ITest.java new file mode 100644 index 000000000..d363f824f --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddress_mocked_ITest.java @@ -0,0 +1,30 @@ +package my.bookshop; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.test.context.ActiveProfiles; + +/** + * Runs tests defined in {@link AdminServiceAddressITestBase} with the default and mocked profile. + * The mocked profile creates a remote services for the API_BUSINESS_PARTNER service (which is however mocked by our own application), + * so the application behaves as if the AdminService and the API_BUSINESS_PARTNER service were provided by two different applications. + */ +@ActiveProfiles({"default", "mocked"}) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, + properties = "cds.remote.services.'[API_BUSINESS_PARTNER]'.destination.name=myself-AdminServiceAddressITest") +public class AdminServiceAddress_mocked_ITest extends AdminServiceAddressITestBase { + + @Test + @Override + public void testAddressesValueHelp() { + super.testAddressesValueHelp(); + } + + @Test + @Override + public void testOrderWithAddress() throws InterruptedException { + super.testOrderWithAddress(); + } + +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceTest.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceTest.java new file mode 100644 index 000000000..2c0cba173 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceTest.java @@ -0,0 +1,96 @@ +package my.bookshop; + +import static cds.gen.adminservice.AdminService_.AUTHORS; +import static cds.gen.adminservice.AdminService_.ORDERS; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.math.BigDecimal; +import java.util.Collections; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.test.context.support.WithMockUser; + +import com.sap.cds.Result; +import com.sap.cds.ql.Insert; +import com.sap.cds.services.ServiceException; +import com.sap.cds.services.utils.CdsErrorStatuses; + +import cds.gen.adminservice.AdminService; +import cds.gen.adminservice.Authors; +import cds.gen.adminservice.OrderItems; +import cds.gen.adminservice.Orders; + +@SpringBootTest +@AutoConfigureMockMvc +public class AdminServiceTest { + + @Autowired + private AdminService.Draft adminService; + + @Test + @WithMockUser(username = "user") + public void testUnauthorizedAccess() { + assertThrows(ServiceException.class, () -> { + adminService.newDraft(Insert.into(AUTHORS).entry(Collections.emptyMap())); + }); + } + + @Test + @WithMockUser(username = "admin") + public void testInvalidAuthorName() { + assertThrows(ServiceException.class, () -> { + Authors author = Authors.create(); + author.setName("little Joey"); + adminService.run(Insert.into(AUTHORS).entry(author)); + }); + } + + @Test + @WithMockUser(username = "admin") + public void testValidAuthorName() { + Authors author = Authors.create(); + author.setName("Big Joey"); + Result result = adminService.run(Insert.into(AUTHORS).entry(author)); + assertEquals(1, result.rowCount()); + } + + @Test + @WithMockUser(username = "admin") + void testCreateOrderWithoutBook() { + Orders order = Orders.create(); + order.setOrderNo("324"); + order.setShippingAddressId("100"); + OrderItems item = OrderItems.create(); + item.setQuantity(1); + item.setAmount(BigDecimal.valueOf(12.12)); + order.setItems(Collections.singletonList(item)); + + // Runtime ensures that book is present in the order item, when it is created. + ServiceException exception = + assertThrows(ServiceException.class, () -> adminService.run(Insert.into(ORDERS).entry(order))); + assertEquals(CdsErrorStatuses.VALUE_REQUIRED.getCodeString(), exception.getErrorStatus().getCodeString()); + } + + @Test + @WithMockUser(username = "admin") + void testCreateOrderWithNonExistingBook() { + Orders order = Orders.create(); + order.setOrderNo("324"); + order.setShippingAddressId("100"); + OrderItems item = OrderItems.create(); + item.setQuantity(1); + item.setAmount(BigDecimal.valueOf(12.12)); + item.setBookId("4a519e61-3c3a-4bd9-ab12-d7e0c5ddaabb"); + order.setItems(Collections.singletonList(item)); + + // Runtime ensures that book exists when order item is created. + ServiceException exception = + assertThrows(ServiceException.class, () -> adminService.run(Insert.into(ORDERS).entry(order))); + assertEquals(CdsErrorStatuses.TARGET_ENTITY_MISSING.getCodeString(), exception.getErrorStatus().getCodeString()); + } + +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/CatalogServiceITest.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/CatalogServiceITest.java new file mode 100644 index 000000000..a3010a370 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/CatalogServiceITest.java @@ -0,0 +1,93 @@ +package my.bookshop; + +import static cds.gen.catalogservice.CatalogService_.REVIEWS; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.not; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; + +import com.sap.cds.ql.Delete; +import com.sap.cds.services.persistence.PersistenceService; + +import cds.gen.catalogservice.Reviews; + +@SpringBootTest +@AutoConfigureMockMvc +public class CatalogServiceITest { + + private static final String booksURI = "/api/browse/Books"; + private static final String addReviewURI = String.format("%s(ID=%s)/CatalogService.addReview", booksURI, "f846b0b9-01d4-4f6d-82a4-d79204f62278"); + + private static final String USER_USER_STRING = "user"; + private static final String ADMIN_USER_STRING = "admin"; + + @Autowired + private MockMvc mockMvc; + + @Autowired + private PersistenceService db; + + @AfterEach + public void cleanup() { + db.run(Delete.from(REVIEWS)); + } + + @Test + public void testDiscountApplied() throws Exception { + mockMvc.perform(get(booksURI + "?$filter=stock gt 200&top=1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.value[0].title").value(containsString("11% discount"))); + } + + @Test + public void testDiscountNotApplied() throws Exception { + mockMvc.perform(get(booksURI + "?$filter=stock lt 100&top=1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.value[0].title").value(not(containsString("11% discount")))); + } + + @Test + public void testCreateReviewNotAuthenticated() throws Exception { + String payload = createTestReview().toJson(); + mockMvc.perform(post(addReviewURI).contentType(MediaType.APPLICATION_JSON).content(payload)) + .andExpect(status().isUnauthorized()); + } + + @Test + @WithMockUser(USER_USER_STRING) + public void testCreateReviewByUser() throws Exception { + String payload = createTestReview().toJson(); + mockMvc.perform(post(addReviewURI).contentType(MediaType.APPLICATION_JSON).content(payload)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.createdBy").value(USER_USER_STRING)); + } + + @Test + @WithMockUser(ADMIN_USER_STRING) + public void testCreateReviewByAdmin() throws Exception { + String payload = createTestReview().toJson(); + mockMvc.perform(post(addReviewURI).contentType(MediaType.APPLICATION_JSON).content(payload)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.createdBy").value(ADMIN_USER_STRING)); + } + + private Reviews createTestReview() { + Reviews review = Reviews.create(); + review.setRating(1); + review.setTitle("title"); + review.setText("text"); + return review; + } + +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/CatalogServiceTest.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/CatalogServiceTest.java new file mode 100644 index 000000000..85684e60b --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/CatalogServiceTest.java @@ -0,0 +1,138 @@ +package my.bookshop; + +import static cds.gen.catalogservice.CatalogService_.BOOKS; +import static cds.gen.catalogservice.CatalogService_.REVIEWS; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.stream.Stream; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.test.context.support.WithMockUser; + +import com.sap.cds.ql.CQL; +import com.sap.cds.ql.Delete; +import com.sap.cds.services.ServiceException; +import com.sap.cds.services.persistence.PersistenceService; + +import cds.gen.catalogservice.Books_; +import cds.gen.catalogservice.CatalogService; +import cds.gen.catalogservice.Reviews; + +@SpringBootTest +public class CatalogServiceTest { + + @Autowired + private CatalogService catalogService; + + @Autowired + private PersistenceService db; + + @AfterEach + public void cleanup() { + db.run(Delete.from(REVIEWS)); + } + + @Test + @WithMockUser(username = "user") + public void testCreateReviewHandler() { + Stream bookReviews = Stream.of( + createReview("f846b0b9-01d4-4f6d-82a4-d79204f62278", 1, "quite bad", "disappointing..."), + createReview("aebdfc8a-0dfa-4468-bd36-48aabd65e663", 5, "great read", "just amazing...")); + + bookReviews.forEach(bookReview -> { + + Books_ ref = CQL.entity(BOOKS).filter(b -> b.ID().eq(bookReview.getBookId())); + Reviews result = catalogService.addReview(ref, bookReview.getRating(), bookReview.getTitle(), bookReview.getText()); + + assertEquals(bookReview.getBookId(), result.getBookId()); + assertEquals(bookReview.getRating(), result.getRating()); + assertEquals(bookReview.getTitle(), result.getTitle()); + assertEquals(bookReview.getText(), result.getText()); + }); + } + + @Test + @WithMockUser(username = "user") + public void testAddReviewWithInvalidRating() { + Stream bookReviews = Stream.of( + // lt 1 is invalid + createReview("f846b0b9-01d4-4f6d-82a4-d79204f62278", 0, "quite bad", "disappointing..."), + // gt 5 is invalid + createReview("9b084139-0b1e-43b6-b12a-7b3669d75f02", 6, "great read", "just amazing...")); + + String message = "Valid rating range needs to be within 1 and 5"; + + bookReviews.forEach(bookReview -> { + Books_ ref = CQL.entity(BOOKS).filter(b -> b.ID().eq(bookReview.getBookId())); + assertThrows(ServiceException.class, () -> catalogService.addReview(ref, bookReview.getRating(), + bookReview.getTitle(), bookReview.getText()), message); + }); + } + + @Test + @WithMockUser(username = "user") + public void testAddReviewForNonExistingBook() { + + String nonExistingBookId = "non-existing"; + String exMessage1 = "You have to specify the book to review"; + String exMessage2 = String.format("A book with the specified ID '%s' does not exist", nonExistingBookId); + + Stream testCases = Stream.of( + // no book provided + new BookReviewTestFixture(createReview(null, 1, "quite bad", "disappointing..."), exMessage1), + // invalid book id + new BookReviewTestFixture(createReview(nonExistingBookId, 5, "great read", "just amazing..."), + exMessage2)); + + testCases.forEach(testCase -> { + Books_ ref = CQL.entity(BOOKS).filter(b -> b.ID().eq(testCase.review.getBookId())); + assertThrows(ServiceException.class, () -> catalogService.addReview(ref, testCase.review.getRating(), + testCase.review.getTitle(), testCase.review.getText()), testCase.exceptionMessage); + }); + } + + @Test + @WithMockUser(username = "user") + public void testAddReviewSameBookMoreThanOnceBySameUser() { + + String bookId = "4a519e61-3c3a-4bd9-ab12-d7e0c5329933"; + Books_ ref = CQL.entity(BOOKS).filter(b -> b.ID().eq(bookId)); + + assertDoesNotThrow(() -> catalogService.addReview(ref, 1, "quite bad", "disappointing...")); + assertThrows(ServiceException.class, () -> catalogService.addReview(ref, 5, "great read", "just amazing..."), + "User not allowed to add more than one review for a given book"); + + String anotherBookId = "9b084139-0b1e-43b6-b12a-7b3669d75f02"; + Books_ anotherRef = CQL.entity(BOOKS).filter(b -> b.ID().eq(anotherBookId)); + + assertDoesNotThrow(() -> catalogService.addReview(anotherRef, 4, "very good", "entertaining...")); + } + + private Reviews createReview(String bookId, Integer rating, String title, String text) { + Reviews review = Reviews.create(); + review.setBookId(bookId); + review.setRating(rating); + review.setTitle(title); + review.setText(text); + return review; + } + + /* + * Holder class for a book review test case. + */ + private class BookReviewTestFixture { + Reviews review; + String exceptionMessage; + + BookReviewTestFixture(Reviews review, String exceptionMessage) { + this.review = review; + this.exceptionMessage = exceptionMessage; + } + } + +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/NotesServiceITest.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/NotesServiceITest.java new file mode 100644 index 000000000..540be4e89 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/NotesServiceITest.java @@ -0,0 +1,192 @@ +package my.bookshop; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.http.HttpHeaders; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.reactive.server.WebTestClient; + +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, + properties = "cds.remote.services.'[API_BUSINESS_PARTNER]'.destination.name=myself-NotesServiceITest") +@ActiveProfiles({"default", "mocked"}) +public class NotesServiceITest { + + private static final String notesURI = "/api/notes/Notes"; + private static final String addressesURI = "/api/notes/Addresses"; + + @Autowired + private WebTestClient client; + + @Test + public void testGetNotes() throws Exception { + client.get().uri(notesURI).headers(this::authenticatedCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.['@context']").isEqualTo("$metadata#Notes") + .jsonPath("$.value[0].ID").isEqualTo("5efc842c-c70d-4ee2-af1d-81c7d257aff7") + .jsonPath("$.value[0].note").isEqualTo("Ring at building 8") + .jsonPath("$.value[0].address_businessPartner").isEqualTo("1000020") + .jsonPath("$.value[0].address_ID").isEqualTo("500") + .jsonPath("$.value[1].ID").isEqualTo("83e2643b-aecc-47d3-9f85-a8ba14eff07d") + .jsonPath("$.value[1].note").isEqualTo("Packages can be dropped off at the reception") + .jsonPath("$.value[1].address_businessPartner").isEqualTo("10401010") + .jsonPath("$.value[1].address_ID").isEqualTo("100") + .jsonPath("$.value[2].ID").isEqualTo("880147b0-8d2d-4ef8-bb52-ae5ae6002fc5") + .jsonPath("$.value[2].note").isEqualTo("Don't deliver packages after 5pm") + .jsonPath("$.value[2].address_businessPartner").isEqualTo("10401010") + .jsonPath("$.value[2].address_ID").isEqualTo("100"); + } + + @Test + public void testGetAddresses() throws Exception { + client.get().uri(addressesURI + "?$filter=businessPartner eq '10401010'").headers(this::authenticatedCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.['@context']").isEqualTo("$metadata#Addresses") + .jsonPath("$.value[0].ID").isEqualTo("100") + .jsonPath("$.value[0].postalCode").isEqualTo("68199") + .jsonPath("$.value[1].ID").isEqualTo("200") + .jsonPath("$.value[1].postalCode").isEqualTo("68789") + .jsonPath("$.value[2].ID").isEqualTo("300") + .jsonPath("$.value[2].postalCode").isEqualTo("14469"); + } + + @Test + public void testGetNoteWithAddress() throws Exception { + client.get().uri(notesURI + "?$expand=address").headers(this::authenticatedCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.['@context']").isEqualTo("$metadata#Notes(address())") + .jsonPath("$.value[0].ID").isEqualTo("5efc842c-c70d-4ee2-af1d-81c7d257aff7") + .jsonPath("$.value[0].note").isEqualTo("Ring at building 8") + .jsonPath("$.value[0].address_businessPartner").isEqualTo("1000020") + .jsonPath("$.value[0].address_ID").isEqualTo("500") + .jsonPath("$.value[0].address.businessPartner").isEqualTo("1000020") + .jsonPath("$.value[0].address.ID").isEqualTo("500") + .jsonPath("$.value[0].address.postalCode").isEqualTo("94304") + .jsonPath("$.value[1].ID").isEqualTo("83e2643b-aecc-47d3-9f85-a8ba14eff07d") + .jsonPath("$.value[1].note").isEqualTo("Packages can be dropped off at the reception") + .jsonPath("$.value[1].address_businessPartner").isEqualTo("10401010") + .jsonPath("$.value[1].address_ID").isEqualTo("100") + .jsonPath("$.value[1].address.businessPartner").isEqualTo("10401010") + .jsonPath("$.value[1].address.ID").isEqualTo("100") + .jsonPath("$.value[1].address.postalCode").isEqualTo("68199") + .jsonPath("$.value[2].ID").isEqualTo("880147b0-8d2d-4ef8-bb52-ae5ae6002fc5") + .jsonPath("$.value[2].note").isEqualTo("Don't deliver packages after 5pm") + .jsonPath("$.value[2].address_businessPartner").isEqualTo("10401010") + .jsonPath("$.value[2].address_ID").isEqualTo("100") + .jsonPath("$.value[2].address.businessPartner").isEqualTo("10401010") + .jsonPath("$.value[2].address.ID").isEqualTo("100") + .jsonPath("$.value[2].address.postalCode").isEqualTo("68199"); + } + + @Test + public void testGetSuppliersWithNotes() throws Exception { + client.get().uri(addressesURI + "?$expand=notes($orderby=ID)&$filter=businessPartner eq '10401010'").headers(this::authenticatedCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.['@context']").isEqualTo("$metadata#Addresses(notes())") + .jsonPath("$.value[0].ID").isEqualTo("100") + .jsonPath("$.value[0].postalCode").isEqualTo("68199") + .jsonPath("$.value[0].notes[0].ID").isEqualTo("83e2643b-aecc-47d3-9f85-a8ba14eff07d") + .jsonPath("$.value[0].notes[0].note").isEqualTo("Packages can be dropped off at the reception") + .jsonPath("$.value[0].notes[0].address_businessPartner").isEqualTo("10401010") + .jsonPath("$.value[0].notes[0].address_ID").isEqualTo("100") + .jsonPath("$.value[0].notes[1].ID").isEqualTo("880147b0-8d2d-4ef8-bb52-ae5ae6002fc5") + .jsonPath("$.value[0].notes[1].note").isEqualTo("Don't deliver packages after 5pm") + .jsonPath("$.value[0].notes[1].address_businessPartner").isEqualTo("10401010") + .jsonPath("$.value[0].notes[1].address_ID").isEqualTo("100") + .jsonPath("$.value[0].notes[2]").doesNotExist() + .jsonPath("$.value[1].ID").isEqualTo("200") + .jsonPath("$.value[1].postalCode").isEqualTo("68789") + .jsonPath("$.value[2].notes").isEmpty() + .jsonPath("$.value[2].ID").isEqualTo("300") + .jsonPath("$.value[2].postalCode").isEqualTo("14469") + .jsonPath("$.value[2].notes").isEmpty(); + } + + @Test + public void testGetNotesToSupplier() throws Exception { + client.get().uri(notesURI + "(ID=5efc842c-c70d-4ee2-af1d-81c7d257aff7,IsActiveEntity=true)/address").headers(this::authenticatedCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.['@context']").isEqualTo("$metadata#Addresses/$entity") + .jsonPath("$.businessPartner").isEqualTo("1000020") + .jsonPath("$.ID").isEqualTo("500") + .jsonPath("$.postalCode").isEqualTo("94304"); + } + + @Test + public void testGetSupplierToNotes() throws Exception { + client.get().uri(addressesURI + "(businessPartner='10401010',ID='100')/notes").headers(this::authenticatedCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.value[0].ID").isEqualTo("83e2643b-aecc-47d3-9f85-a8ba14eff07d") + .jsonPath("$.value[0].note").isEqualTo("Packages can be dropped off at the reception") + .jsonPath("$.value[0].address_businessPartner").isEqualTo("10401010") + .jsonPath("$.value[0].address_ID").isEqualTo("100") + .jsonPath("$.value[1].ID").isEqualTo("880147b0-8d2d-4ef8-bb52-ae5ae6002fc5") + .jsonPath("$.value[1].note").isEqualTo("Don't deliver packages after 5pm") + .jsonPath("$.value[1].address_businessPartner").isEqualTo("10401010") + .jsonPath("$.value[1].address_ID").isEqualTo("100") + .jsonPath("$.value[2]").doesNotExist(); + } + + @Test + public void testGetSupplierToSpecificNote() throws Exception { + client.get().uri(addressesURI + "(businessPartner='10401010',ID='100')/notes(ID=83e2643b-aecc-47d3-9f85-a8ba14eff07d,IsActiveEntity=true)") + .headers(this::authenticatedCredentials) + .exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.ID").isEqualTo("83e2643b-aecc-47d3-9f85-a8ba14eff07d") + .jsonPath("$.note").isEqualTo("Packages can be dropped off at the reception") + .jsonPath("$.address_businessPartner").isEqualTo("10401010") + .jsonPath("$.address_ID").isEqualTo("100"); + } + + @Test + public void testGetNotesWithNestedExpands() throws Exception { + client.get().uri(notesURI + "?$select=note&$expand=address($select=postalCode;$expand=notes($select=note))&$top=1").headers(this::authenticatedCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.value[0].ID").isEqualTo("5efc842c-c70d-4ee2-af1d-81c7d257aff7") + .jsonPath("$.value[0].note").isEqualTo("Ring at building 8") + .jsonPath("$.value[0].address.businessPartner").isEqualTo("1000020") + .jsonPath("$.value[0].address.ID").isEqualTo("500") + .jsonPath("$.value[0].address.postalCode").isEqualTo("94304") + .jsonPath("$.value[0].address.notes[0].ID").isEqualTo("5efc842c-c70d-4ee2-af1d-81c7d257aff7") + .jsonPath("$.value[0].address.notes[0].note").isEqualTo("Ring at building 8") + .jsonPath("$.value[0].address.notes[1]").doesNotExist() + .jsonPath("$.value[1]").doesNotExist(); + } + + @Test + public void testGetAddressesWithNestedExpands() throws Exception { + client.get().uri(addressesURI + "?$select=postalCode&$expand=notes($select=note;$expand=address($select=postalCode))&$filter=businessPartner eq '1000020'") + .headers(this::authenticatedCredentials) + .exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.value[0].businessPartner").isEqualTo("1000020") + .jsonPath("$.value[0].ID").isEqualTo("400") + .jsonPath("$.value[0].postalCode").isEqualTo("19073") + .jsonPath("$.value[0].notes").isEmpty() + .jsonPath("$.value[1].businessPartner").isEqualTo("1000020") + .jsonPath("$.value[1].ID").isEqualTo("500") + .jsonPath("$.value[1].postalCode").isEqualTo("94304") + .jsonPath("$.value[1].notes[0].ID").isEqualTo("5efc842c-c70d-4ee2-af1d-81c7d257aff7") + .jsonPath("$.value[1].notes[0].note").isEqualTo("Ring at building 8") + .jsonPath("$.value[1].notes[0].address.businessPartner").isEqualTo("1000020") + .jsonPath("$.value[1].notes[0].address.ID").isEqualTo("500") + .jsonPath("$.value[1].notes[0].address.postalCode").isEqualTo("94304") + .jsonPath("$.value[1].notes[1]").doesNotExist() + .jsonPath("$.value[2]").doesNotExist(); + } + + private void authenticatedCredentials(HttpHeaders headers) { + headers.setBasicAuth("authenticated", ""); + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/RatingCalculatorTest.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/RatingCalculatorTest.java new file mode 100644 index 000000000..816fe9b76 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/RatingCalculatorTest.java @@ -0,0 +1,37 @@ +package my.bookshop; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.math.BigDecimal; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +public class RatingCalculatorTest { + + /* + * Holder class for a book rating calculation test case. + */ + private class RatingTestFixture { + Stream ratings; + double expectedAvg; + + RatingTestFixture(Stream ratings, double expectedAvg) { + this.ratings = ratings; + this.expectedAvg = expectedAvg; + } + } + + @Test + public void testGetAvgRating() { + RatingTestFixture f1 = new RatingTestFixture(Stream.of(1.0, 2.0, 3.0, 4.0, 5.0), 3.0); + RatingTestFixture f2 = new RatingTestFixture(Stream.of(1.3, 2.4, 3.5, 4.9, 5.1), 3.4); + RatingTestFixture f3 = new RatingTestFixture(Stream.of(2.1, 4.0, 2.7, 3.8, 4.9), 3.5); + + Stream.of(f1, f2, f3).forEach(f -> { + BigDecimal avgRating = RatingCalculator.getAvgRating(f.ratings); + assertEquals(f.expectedAvg, avgRating.doubleValue()); + }); + } + +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/handlers/CatalogServiceHandlerTest.java b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/handlers/CatalogServiceHandlerTest.java new file mode 100644 index 000000000..5e97c5557 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/handlers/CatalogServiceHandlerTest.java @@ -0,0 +1,30 @@ +package my.bookshop.handlers; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +import com.sap.cds.services.request.FeatureTogglesInfo; + +import cds.gen.catalogservice.Books; + +public class CatalogServiceHandlerTest { + + @Test + public void testDiscountHandler() { + Books book1 = Books.create(); + book1.setTitle("Book 1"); + book1.setStock(10); + Books book2 = Books.create(); + book2.setTitle("Book 2"); + book2.setStock(200); + + CatalogServiceHandler handler = new CatalogServiceHandler(null, null, null, FeatureTogglesInfo.create(), null, null); + handler.discountBooks(Stream.of(book1, book2)); + + assertEquals("Book 1", book1.getTitle(), "Book 1 was discounted"); + assertEquals("Book 2 -- 11% discount", book2.getTitle(), "Book 2 was not discounted"); + } +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/resources/META-INF/native-image/native-image.properties b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/resources/META-INF/native-image/native-image.properties new file mode 100644 index 000000000..e799b212f --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/resources/META-INF/native-image/native-image.properties @@ -0,0 +1 @@ +Args = --initialize-at-build-time=com.fasterxml.aalto.in.ReaderConfig,com.fasterxml.aalto.impl.CommonConfig diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/resources/META-INF/native-image/reflect-config.json b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/resources/META-INF/native-image/reflect-config.json new file mode 100644 index 000000000..fc793bf32 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/src/test/resources/META-INF/native-image/reflect-config.json @@ -0,0 +1,6 @@ +[ +{ + "name": "org.hamcrest.TypeSafeMatcher", + "queryAllDeclaredMethods": true +} +] diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/srv/user-service.cds b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/user-service.cds new file mode 100644 index 000000000..080957ac0 --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/srv/user-service.cds @@ -0,0 +1,10 @@ +using {my.bookshop as my} from '../db/books'; + +service UserService @(requires: [ + 'admin', + 'system-user' +]) { + @odata.draft.enabled + entity Notebooks as projection on my.Notebooks; + entity Writers as projection on my.Writers; +} \ No newline at end of file diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/xs-security-mt.json b/app/multi-tenant/central-space/cloud-cap-samples-java/xs-security-mt.json new file mode 100644 index 000000000..ca82f740b --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/xs-security-mt.json @@ -0,0 +1,37 @@ +{ + "scopes": [ + { + "name": "$XSAPPNAME.admin", + "description": "admin" + }, + { + "name": "$XSAPPNAME.mtcallback", + "description": "Multi Tenancy Callback Access", + "grant-as-authority-to-apps": [ + "$XSAPPNAME(application,sap-provisioning,tenant-onboarding)" + ] + }, + { + "name": "$XSAPPNAME.mtdeployment", + "description": "Scope to trigger a re-deployment of the database artifacts" + }, + { + "name": "$XSAPPNAME.cds.ExtensionDeveloper", + "description": "Extend CAP applications via extension projects" + } + ], + "authorities-inheritance": false, + "authorities": [ + "$XSAPPNAME.mtdeployment" + ], + + "role-templates": [ + { + "name": "admin", + "description": "generated", + "scope-references": [ + "$XSAPPNAME.admin" + ] + } + ] +} diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/xs-security.json b/app/multi-tenant/central-space/cloud-cap-samples-java/xs-security.json new file mode 100644 index 000000000..2d932db2b --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/xs-security.json @@ -0,0 +1,18 @@ +{ + "scopes": [ + { + "name": "$XSAPPNAME.admin", + "description": "admin" + } + ], + "role-templates": [ + { + "name": "admin", + "description": "generated", + "scope-references": [ + "$XSAPPNAME.admin" + ] + } + + ] +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/.cdsprettier.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/.cdsprettier.json new file mode 100644 index 000000000..f3d9ca868 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/.cdsprettier.json @@ -0,0 +1,12 @@ +{ + "alignExpressionsAndConditions": true, + "alignExprAndCondWithinBlock": true, + "alignCompositionStructToRight": true, + "keepOriginalEmptyLines": false, + "openingBraceInNewLine": false, + "alignValuesInAnnotations": true, + "alignColonsInAnnotations": true, + "alignPostAnnotations": true, + "alignPreAnnotations": true, + "alignTypes": true +} \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/.cdsrc.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/.cdsrc.json new file mode 100644 index 000000000..0adb9aa2a --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/.cdsrc.json @@ -0,0 +1,20 @@ +{ + "requires": { + "multitenancy": true, + "extensibility": true, + "toggles": true + }, + "odata": { + "version": "v4" + }, + "fiori": { + "draft_messages": false + }, + "profile": "with-mtx-sidecar", + "cdsc": { + "newParser": true + }, + "sql": { + "native_hana_associations": false + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/.github/workflows/maven.yml b/app/multi-tenant/personal-space/cloud-cap-samples-java/.github/workflows/maven.yml new file mode 100644 index 000000000..f083578d7 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/.github/workflows/maven.yml @@ -0,0 +1,30 @@ +# This workflow will build a Java project with Maven +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: Java CI with Maven + +on: + push: + branches: + - main + - postgres + pull_request: + branches: + - main + - postgres + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up JDK + uses: actions/setup-java@v4 + with: + java-version: 21 + distribution: 'sapmachine' + - name: Build with Maven + run: mvn -ntp -B clean install diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/.gitignore b/app/multi-tenant/personal-space/cloud-cap-samples-java/.gitignore new file mode 100644 index 000000000..f9986b41c --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/.gitignore @@ -0,0 +1,38 @@ +gen/ +edmx/ +schema-h2.sql +default-env.json +openapi.json +.env +.values.yaml + +bin/ +target/ +.java-version +.flattened-pom.xml +.classpath +.project +.settings +.vscode +.idea +*.iml + +node/ +node_modules/ + +.mta/ +*.mtar +mta.yaml + +*.log* +gc_history* +hs_err* +.DS_Store + +*.db +*.sqlite* + +.cdsrc-private.json + +/chart/ +.reloadtrigger diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/.reuse/dep5 b/app/multi-tenant/personal-space/cloud-cap-samples-java/.reuse/dep5 new file mode 100644 index 000000000..57d1ebed0 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/.reuse/dep5 @@ -0,0 +1,29 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: cloud-cap-samples-java +Upstream-Contact: +Source: https://github.com/SAP-samples/cloud-cap-samples-java +Disclaimer: The code in this project may include calls to APIs (“API Calls”) of + SAP or third-party products or services developed outside of this project + (“External Products”). + “APIs” means application programming interfaces, as well as their respective + specifications and implementing code that allows software to communicate with + other software. + API Calls to External Products are not licensed under the open source license + that governs this project. The use of such API Calls and related External + Products are subject to applicable additional agreements with the relevant + provider of the External Products. In no event shall the open source license + that governs this project grant any rights in or to any External Products,or + alter, expand or supersede any terms of the applicable additional agreements. + If you have a valid license agreement with SAP for the use of a particular SAP + External Product, then you may make use of any API Calls included in this + project’s code for that SAP External Product, subject to the terms of such + license agreement. If you do not have a valid license agreement for the use of + a particular SAP External Product, then you may only make use of any API Calls + in this project for that SAP External Product for your internal, non-productive + and non-commercial test and evaluation of such API Calls. Nothing herein grants + you any rights to use or access any SAP External Product, or provide any third + parties the right to use of access any SAP External Product, through API Calls. + +Files: * +Copyright: 2019-2020 SAP SE or an SAP affiliate company and cap-cloud-samples-java +License: Apache-2.0 diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/.tours/sample-tour.tour b/app/multi-tenant/personal-space/cloud-cap-samples-java/.tours/sample-tour.tour new file mode 100644 index 000000000..1847fb477 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/.tours/sample-tour.tour @@ -0,0 +1,201 @@ +{ + "$schema": "https://aka.ms/codetour-schema", + "title": "CAP Bookshop Sample", + "steps": [ + { + "file": "README.md", + "description": "### Welcome to CAP Samples for Java!\n\nThis tour leads you through a sample project for the [SAP Cloud Application Programming Model (CAP)](https://cap.cloud.sap), explaining some important concepts.\n\nLet's get started!", + "line": 2, + "title": "Welcome" + }, + { + "file": "README.md", + "description": "### Bookshop Sample\n\nThe sample implements a simple bookshop demonstrating selected features of CAP and introduces some essential concepts of CAP for Java:\n\n- [Project Setup](https://cap.cloud.sap/docs/java/getting-started) and [Layouts](https://cap.cloud.sap/docs/java/getting-started#project-layout)\n- [Domain Modeling](https://cap.cloud.sap/docs/guides/domain-models)\n- [Defining Services](https://cap.cloud.sap/docs/guides/services#defining-services)\n- [Generic Providers](https://cap.cloud.sap/docs/guides/generic)\n- [Adding Custom Logic](https://cap.cloud.sap/docs/java/provisioning-api)\n- [Using Databases](https://cap.cloud.sap/docs/guides/databases)", + "line": 33 + }, + { + "file": "db/books.cds", + "description": "### Entity and Type Definitions\n\nEvery CAP project usually starts with the [domain model](https://cap.cloud.sap/docs/guides/domain-models). It defines the entities and types you can use in the services your application wants to offer. Showcased here are some entity definitions which are used by the bookshop application, using [CDL](https://cap.cloud.sap/docs/cds/cdl).\n\nConcepts used:\n\n- [Entity and Type Definitions](https://cap.cloud.sap/docs/cds/cdl#entity-and-type-definitions)\n- [Associations & Compositions](https://cap.cloud.sap/docs/cds/cdl#associations)\n- [Input Validation](https://cap.cloud.sap/docs/cds/annotations#input-validation)\n- [Declaring Localized Data](https://cap.cloud.sap/docs/guides/localized-data#declaring-localized-data)", + "line": 55, + "selection": { + "start": { + "line": 1, + "character": 1 + }, + "end": { + "line": 55, + "character": 1 + } + } + }, + { + "file": "srv/cat-service.cds", + "description": "### Service Definitions\n\nA [service](https://cap.cloud.sap/docs/cds/cdl#service-definitions) interface exposes chosen entities of your domain model for consumption. The endpoint of the exposed service is usually constructed by its name following specific conventions. Here, however the endpoint path to the `CatalogService` is overwritten by the `@path : 'browse'` annotation.\n\nThis `CatalogService` showcases the API for browsing books and adding reviews and demonstrates:\n\n- [Services](https://cap.cloud.sap/docs/java/consumption-api)\n- [Import Directives](https://cap.cloud.sap/docs/cds/cdl#imports)\n- [Namespaces](https://cap.cloud.sap/docs/cds/cdl#namespaces)\n- [Views and Projections](https://cap.cloud.sap/docs/cds/cdl#views)\n- [Annotations](https://cap.cloud.sap/docs/cds/cdl#annotations)\n- [Bound and Unbound Actions](https://cap.cloud.sap/docs/cds/cdl#actions)\n- [Restrictions](https://cap.cloud.sap/docs/guides/authorization#restrictions)", + "line": 35, + "selection": { + "start": { + "line": 1, + "character": 1 + }, + "end": { + "line": 35, + "character": 2 + } + } + }, + { + "file": "srv/admin-service.cds", + "description": "### Service Definitions\n\nHere is another example of a service interface, demonstrating:\n\n- [Restriction using `@requires`](https://cap.cloud.sap/docs/guides/authorization#requires)\n- [Search Capabilities](https://cap.cloud.sap/docs/guides/generic#search-capabilities)\n- Enablement of [Draft-Based Editing](https://cap.cloud.sap/docs/advanced/fiori#fiori-draft-support) for exposed entities", + "line": 46, + "selection": { + "start": { + "line": 1, + "character": 1 + }, + "end": { + "line": 46, + "character": 1 + } + } + }, + { + "file": "srv/src/main/java/my/bookshop/handlers/CatalogServiceHandler.java", + "description": "### Event Handler\n\nAfter defining your domain model and services you can [implement event handlers](https://cap.cloud.sap/docs/java/application-services) reacting to events triggered by these services. This file, for example, showcases an [event handler](https://cap.cloud.sap/docs/java/provisioning-api) for the `CatalogService`. There are various handler implementations reacting to specific [event phases](https://cap.cloud.sap/docs/java/provisioning-api#phases), as showcased in the next steps of this tour.", + "selection": { + "start": { + "line": 77, + "character": 2 + }, + "end": { + "line": 180, + "character": 3 + } + } + }, + { + "file": "srv/src/main/java/my/bookshop/handlers/CatalogServiceHandler.java", + "description": "### Event Handler\n\nThe method `beforeAddReview` demonstrated here is used to validate reviews that are about to be persisted, checking whether the author of the review already created one for the given book. The `ServiceException` thrown in such a case aborts further processing of the current event (of adding a review). The method is bound to the `Before` [event phase](https://cap.cloud.sap/docs/java/provisioning-api#phases), meaning it will be triggerd before the core processing of the event. In the next steps you will see some other event phase handling examples.\n\nThe query run against the database for the check is constructed via the [Query Builder Java API](https://cap.cloud.sap/docs/java/query-api#the-query-builders-java-api).\n\nConcepts used:\n\n- [Event Phase: `Before`](https://cap.cloud.sap/docs/java/provisioning-api#before)\n- [Building CQN Queries](https://cap.cloud.sap/docs/java/query-api)\n- [Indicating Errors](https://cap.cloud.sap/docs/java/indicating-errors)\n- [Static CDS Model](https://cap.cloud.sap/docs/java/advanced#staticmodel)", + "line": 94, + "selection": { + "start": { + "line": 77, + "character": 2 + }, + "end": { + "line": 94, + "character": 3 + } + } + }, + { + "file": "srv/src/main/java/my/bookshop/handlers/CatalogServiceHandler.java", + "description": "### Event Handler\n\nThe `onAddReview` method is bound to the `On` phase of the `AddReview` event, as defined by the bound action in the [`CatalogService`](srv/cat-service.cds). Aside from the `Insert` [query execution](https://cap.cloud.sap/docs/java/query-execution#queries) demonstrated here, you can also see how to [complete the event processing](https://cap.cloud.sap/docs/java/provisioning-api#eventcompletion) necessary in the `On` phase. In this example we are setting the `Reviews` object from the query result in the event context.\n\nConcepts used:\n\n- [Event Phase: `On`](https://cap.cloud.sap/docs/java/provisioning-api#on)\n- [Event Contexts](https://cap.cloud.sap/docs/java/provisioning-api#eventcontext)\n- [Building CQN Queries](https://cap.cloud.sap/docs/java/query-api)\n- [Static CDS Model](https://cap.cloud.sap/docs/java/advanced#staticmodel)", + "line": 115, + "selection": { + "start": { + "line": 96, + "character": 2 + }, + "end": { + "line": 115, + "character": 3 + } + } + }, + { + "file": "srv/cat-service.cds", + "description": "### Bound Action\n\nThe [bound action](https://cap.cloud.sap/docs/cds/cdl#actions) `addReview` here is bound to the `Books` entity within the [`CatalogService`](srv/cat-service.cds). Modeling an action provides you with a more specific [event context](https://cap.cloud.sap/docs/java/provisioning-api#eventcontext) object, such as the `AddReviewContext`, which is used, as shown in the previous step, to implement the `AddReview` event processing.", + "line": 10, + "selection": { + "start": { + "line": 10, + "character": 9 + }, + "end": { + "line": 10, + "character": 91 + } + } + }, + { + "file": "srv/cat-service.cds", + "description": "### Unbound Action\n\nIn contrast, `submitOrder` is modeled as an [unbound action](https://cap.cloud.sap/docs/cds/cdl#actions), meaning it is not bound to an individual entity as `addReview` is bound to `Books`.\n\n[Actions and Functions](https://cap.cloud.sap/docs/java/application-services#actions) as the examples shown here and in the previous step, are generally used to enhance your application service with custom operations.", + "line": 21, + "selection": { + "start": { + "line": 19, + "character": 5 + }, + "end": { + "line": 21, + "character": 7 + } + } + }, + { + "file": "srv/src/main/java/my/bookshop/handlers/BookRatingInitialization.java", + "description": "### Application Start-Up\n\nYou can not only register event handlers for your services, but also handlers that are executed during application start-up. As demonstrated here, for example, we initialize the average rating for all books in the bookshop based on their review ratings, using the [`After`](https://cap.cloud.sap/docs/java/provisioning-api#after) phase of the [`ApplicationLifecycleService.EVENT_APPLICATION_PREPARED`](https://www.javadoc.io/doc/com.sap.cds/cds-services-api/latest/com/sap/cds/services/application/ApplicationPreparedEventContext.html) event.", + "line": 30, + "selection": { + "start": { + "line": 27, + "character": 2 + }, + "end": { + "line": 30, + "character": 3 + } + } + }, + { + "file": "srv/src/main/java/my/bookshop/config/DestinationConfiguration.java", + "description": "### Application Start-Up\n\nAnother example of this you can find here in the `DestinationConfiguration` handler.", + "line": 35, + "selection": { + "start": { + "line": 22, + "character": 2 + }, + "end": { + "line": 35, + "character": 3 + } + } + }, + { + "file": "srv/src/main/java/my/bookshop/handlers/AdminServiceHandler.java", + "description": "### SAP Fiori Drafts Support\n\nHere, you can see a handler bound to events of the [SAP Fiori Draft](https://cap.cloud.sap/docs/java/fiori-drafts) flow. Draft-specific events are enabled by annotating entities with `@odata.draft.enabled` as in the [`AdminService`](srv/admin-service.cds).\n\nConcepts used:\n\n- [Draft-based Editing](https://cap.cloud.sap/docs/advanced/fiori#fiori-draft-support)", + "line": 158, + "selection": { + "start": { + "line": 142, + "character": 2 + }, + "end": { + "line": 158, + "character": 3 + } + } + }, + { + "file": "app/browse/fiori-service.cds", + "description": "### SAP Fiori Elements Support\n\nCAP for Java supports SAP Fiori Elements annotations out-of-the-box. The `fiori-service.cds` files in the [app](app) folder altogether add a [SAP Fiori elements application](https://cap.cloud.sap/docs/advanced/fiori) to bookshop, thereby introducing to:\n - [OData Annotations](https://cap.cloud.sap/docs/advanced/odata) in `.cds` files\n - Support for [SAP Fiori Draft](https://cap.cloud.sap/docs/advanced/fiori#fiori-draft-support)\n - Support for [Value Helps](https://cap.cloud.sap/docs/advanced/fiori#value-help-support)\n - Serving SAP Fiori apps locally\n\n[A Vue.js app](app/vue/index.html) is served as well.\n", + "line": 177, + "selection": { + "start": { + "line": 1, + "character": 1 + }, + "end": { + "line": 201, + "character": 1 + } + } + }, + { + "title": "Summary", + "description": "### Summary\n\nThat's it! You have seen:\n\n- Entity and Type Definitions\n- Service Definitions\n- Event Handler\n- Bound and Unbound Actions\n- Fiori Draft Support\n- SAP Fiori Elements Support\n\nFor more information and details, check our [CAP](https://cap.cloud.sap/docs/) documentation." + } + ], + "description": "Demonstrating CAP for Java" +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/LICENSE b/app/multi-tenant/personal-space/cloud-cap-samples-java/LICENSE new file mode 100644 index 000000000..67db85882 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/LICENSE @@ -0,0 +1,175 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + 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 + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + 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 + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + 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. diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/LICENSES/Apache-2.0.txt b/app/multi-tenant/personal-space/cloud-cap-samples-java/LICENSES/Apache-2.0.txt new file mode 100644 index 000000000..4ed90b952 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/LICENSES/Apache-2.0.txt @@ -0,0 +1,208 @@ +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, +AND DISTRIBUTION + + 1. Definitions. + + + +"License" shall mean the terms and conditions for use, reproduction, and distribution +as defined by Sections 1 through 9 of this document. + + + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + + + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct +or indirect, to cause the direction or management of such entity, whether +by contract or otherwise, or (ii) ownership of fifty percent (50%) or more +of the outstanding shares, or (iii) beneficial ownership of such entity. + + + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions +granted by this License. + + + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + + + +"Object" form shall mean any form resulting from mechanical transformation +or translation of a Source form, including but not limited to compiled object +code, generated documentation, and conversions to other media types. + + + +"Work" shall mean the work of authorship, whether in Source or Object form, +made available under the License, as indicated by a copyright notice that +is included in or attached to the work (an example is provided in the Appendix +below). + + + +"Derivative Works" shall mean any work, whether in Source or Object 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 the original version +of the Work and any modifications or additions to that Work or Derivative +Works thereof, that is intentionally submitted to Licensor for inclusion in +the Work by the copyright owner or by an individual or Legal Entity authorized +to submit on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication +sent to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor +for the purpose of discussing and improving the Work, but 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 on behalf +of whom a Contribution has been received by Licensor and subsequently incorporated +within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this +License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable copyright license to reproduce, prepare +Derivative Works of, publicly display, publicly perform, sublicense, and distribute +the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of 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. diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/README.md b/app/multi-tenant/personal-space/cloud-cap-samples-java/README.md new file mode 100644 index 000000000..685fb0d96 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/README.md @@ -0,0 +1,591 @@ + +# Welcome to CAP Samples for Java + +![CI status](https://github.com/SAP-samples/cloud-cap-samples-java/workflows/Java%20CI%20with%20Maven/badge.svg) +[![REUSE status](https://api.reuse.software/badge/github.com/SAP-samples/cloud-cap-samples-java)](https://api.reuse.software/info/github.com/SAP-samples/cloud-cap-samples-java) + +Welcome to the bookshop-java project. It demonstrates how to build business applications using the [CAP Java SDK](https://cap.cloud.sap) providing a book shop web application as an example. The application in this project enables browsing books, managing books, and managing orders. + +![Book Object Page](assets/readmeImages/BookPage.png) + + +## Outline + +- [Overview](#overview) + - [Demonstrated Features](#demonstrated-features) +- [Getting Started](#getting-started) + - [Prerequisites](#prerequisites) + - [Clone Build & Run](#clone-build--run) + - [Using VS Code](#using-vs-code) + - [Using Eclipse](#using-eclipse) + - [Building and Running](#building-and-running) + - [Using IntelliJ Idea (Community and Ultimate)](#using-intellij-idea-community-and-ultimate) + - [Database Setup and Spring Profiles](#database-setup-and-spring-profiles) + - [API_BUSINESS_PARTNER Remote Service and Spring Profiles](#api_business_partner-remote-service-and-spring-profiles) + - [Deploy to SAP Business Technology Platform, Cloud Foundry](#deploy-to-sap-business-technology-platform-cloud-foundry) + - [Deploy to SAP Business Technology Platform, Kyma Runtime](#deploy-to-sap-business-technology-platform-kyma-runtime) + - [Setup Authorizations in SAP Business Technology Platform](#setup-authorizations-in-sap-business-technology-platform) +- [Code Tour](#code-tour) +- [Get Support](#get-support) +- [License](#license) + + +# Overview + +This sample application shows how to conveniently create business applications based on **CDS domain models**, persisting data with **H2**, or **SAP HANA**, and exposing an **OData V4** frontend with an **SAP Fiori** frontend on top. + +This sample uses Spring Boot as an **application framework**. Although a CAP Java application isn’t required to build on Spring Boot, it’s the first choice of framework, as it’s seamlessly integrated. + +The **domain models** are defined using [CDS entity definitions](https://cap.cloud.sap/docs/cds/cdl#entity-and-type-definitions). + +By default, an in-memory H2 database is used for **data persistency**. Once productively deployed to SAP Business Technology Platform, SAP HANA can be used. + +**Services** are defined using [CDS Service Models](https://cap.cloud.sap/docs/cds/cdl#services). The **OData V4 Protocol Adapter** translates the CDS service models into corresponding OData schemas and maps the incoming OData requests to the corresponding CDS services. + +Although CAP provides generic **event handlers** to serve most CRUD requests out-of-the-box, it’s possible to add business logic through [Custom Event Handlers](https://cap.cloud.sap/docs/get-started/in-a-nutshell#adding-custom-logic). + +A SAP Fiori UI is added using predefined SAP Fiori elements templates. **[SAP Fiori annotations](https://cap.cloud.sap/docs/advanced/fiori#fiori-annotations)** add information to the service definitions, on how to render the data. + +CAP provides built-in multitenancy support with out-of-the box tenant isolation. The sample application demonstrates usage of MTX sidecar based on [streamlined MTX](https://cap.cloud.sap/docs/guides/deployment/as-saas?impl-variant=java) and can be deployed as multitenant application. The [deprecated classic MTX](https://cap.cloud.sap/docs/java/multitenancy) setup is shown in the [mtx-classic branch](https://github.com/SAP-samples/cloud-cap-samples-java/tree/mtx-classic) for reference. + +## Demonstrated Features + +Framework and Infrastructure related Features: + +- [Application configuration](https://cap.cloud.sap/docs/java/development#application-configuration) for Spring and CDS using [application.yaml](srv/src/main/resources/application.yaml) +- [Mocking users](/srv/src/main/resources/application.yaml) for local development +- [Authentication & Authorization](https://cap.cloud.sap/docs/java/security) (including user-specific restrictions with `@restrict` in the [Admin Service](/srv/admin-service.cds)) +- [Cloud Foundry Deployment using MTA](https://cap.cloud.sap/docs/advanced/deploy-to-cloud#deploy-using-mta) with XSUAA [Service Bindings](mta-single-tenant.yaml) +- Application Router configuration including authentication via the XSUAA Service. See [package.json](app/package.json), [xs-app.json](app/xs-app.json) and [xs-security.json](xs-security.json) +- [Multitenancy configuration](https://cap.cloud.sap/docs/java/multitenancy) via [mta-multi-tenant.yaml](mta-multi-tenant.yaml), [.cdsrc.json](.cdsrc.json), [sidecar module](mtx-sidecar) +- [Feature toggles](https://cap.cloud.sap/docs/guides/extensibility/feature-toggles?impl-variant=java#limitations). In CF, features can be toggled by assigning the roles `expert` or `premium-customer` to the user. +- [Messaging configuration and handlers](https://cap.cloud.sap/docs/java/messaging-foundation) with local messaging and message brokers. +- Consumption of [Remote services](https://cap.cloud.sap/docs/java/remote-services) in [srv/external.cds] and [srv/notes-mashup.cds] + +Domain Model related Features: + +- [CDS Query Language with a Static CDS Model](https://cap.cloud.sap/docs/java/advanced#staticmodel) in the [Admin Service](srv/src/main/java/my/bookshop/handlers/AdminServiceHandler.java) +- Use of [Aspects](https://cap.cloud.sap/docs/cds/cdl#aspects) in the Model Definition such as the [`managed` or `cuid` Aspect](https://cap.cloud.sap/docs/cds/common#common-reuse-aspects) in [Books](db/books.cds) +- [Input validation](https://cap.cloud.sap/docs/cds/annotations#input-validation) using model annotation `@assert.format` +- [Data Localization](https://cap.cloud.sap/docs/guides/localized-data) for [Books](db/books.cds) +- Use of [Media Data](https://cap.cloud.sap/docs/guides/providing-services#media-data) in [Books](db/books.cds) and [AdminService](srv/admin-service.cds) + +Service Model related Features: + +- [Custom event handlers](https://cap.cloud.sap/docs/java/provisioning-api) such as the [Custom business logic for the Admin Service](srv/src/main/java/my/bookshop/handlers/AdminServiceHandler.java) +- [Custom actions](https://cap.cloud.sap/docs/cds/cdl#actions) such as `addToOrder` in the [Admin Service](srv/admin-service.cds). The Action implementation is in the [Admin Service Event Handler](srv/src/main/java/my/bookshop/handlers/AdminServiceHandler.java) +- Add annotations for [searchable elements](https://github.wdf.sap.corp/pages/cap/java/query-api#select) in the [Admin Service](srv/admin-service.cds) +- [Localized Messages](https://cap.cloud.sap/docs/java/indicating-errors) in the [Admin Service Event Handler](srv/src/main/java/my/bookshop/handlers/AdminServiceHandler.java) +- role- and instance-based restrictions in [AdminService](srv/admin-service.cds) and [ReviewService](srv/review-service.cds) +- Use of [`@cds.persistence.skip`](https://cap.cloud.sap/docs/advanced/hana#cdspersistenceskip) in [AdminService](srv/admin-service.cds) +- [Media Data](https://cap.cloud.sap/docs/guides/providing-services#media-data) processing in the [Admin Service Event Handler](srv/src/main/java/my/bookshop/handlers/AdminServiceHandler.java) + +User Interface related Features: + +- Support for [SAP Fiori Elements](https://cap.cloud.sap/docs/advanced/fiori) +- [SAP Fiori Draft based Editing](https://cap.cloud.sap/docs/advanced/fiori#draft-support) for [Books, Orders](srv/admin-service.cds) and [Reviews](srv/review-service.cds) +- [SAP Fiori annotations](https://cap.cloud.sap/docs/advanced/fiori#fiori-annotations) specific for [Browse Books](app/browse/fiori-service.cds), [Manage Books](app/admin/fiori-service.cds), [Manage Orders](app/orders/fiori-service.cds), [Manage Reviews](app/reviews/fiori-service.cds) and [common annotations](app/common.cds), which apply to all UI's +- UI Annotations for custom actions in the [Browse Books](app/browse/fiori-service.cds) and [Manage Books](app/admin/fiori-service.cds) UI, including annotations for a button and a popup +- [Value Help](https://cap.cloud.sap/docs/cds/annotations#odata) for [Books](app/orders/fiori-service.cds) and [Authors](app/common.cds) +- [Model Localization](https://cap.cloud.sap/docs/guides/i18n) for [English](app/_i18n/i18n.properties) and [German](app/_i18n/i18n_de.properties) language for static texts +- [Custom File Upload extension](app/admin/webapp/extension/Upload.js) which provides a button for uploading `CSV` files +- A simple Swagger UI for the CatalogService API at + +CDS Maven Plugin Features: + +- Install [Node.js](srv/pom.xml#L157) in the default version. +- Install a [configured version](pom.xml#L24) of [@sap/cds-dk](srv/pom.xml#L167). +- Execute arbitrary [CDS](srv/pom.xml#L177) commands. +- [Generate](srv/pom.xml#L195) Java POJOs for type-safe access to the CDS model. +- [Clean](srv/pom.xml#L150) project from artifacts of the previous build. + +# Getting Started + +The following sections describe how to set up, build, and run the project. + +## Prerequisites + +Make sure you have set up a development environment (that means, you’ve installed the CDS Compiler, Java, and Apache Maven) [as described here](https://cap.cloud.sap/docs/java/getting-started). + +## Clone Build & Run + +1. Clone the project: + + ```bash + git clone https://github.com/SAP-samples/cloud-cap-samples-java.git + ``` + +2. Build and run the application: + + ``` + mvn spring-boot:run + ``` + +> [!NOTE] +> Please note that some IDEs may interfere with their autobuild when launching the application from the CLI using Maven. Therefore, please ensure that no IDEs are running in parallel or launch the application natively from your preferred IDE as described below. + +3. Use the following links in the browser to check if everything works fine: + + - http://localhost:8080: This should show the automatically generated index page of served paths. + - http://localhost:8080/fiori.html: This is the actual bookshop application UI. + - http://localhost:8080/swagger/index.html: This is providing a Swagger UI for the CatalogService API. + +You'll start with a predefined stock of books as this procedure starts the bookshop application with a CSV-initialized in-memory H2 database. + +Two mock users in addition to the [default mock users](https://cap.cloud.sap/docs/java/security#preconfigured-mock-users) +are defined for local development: +- User: `user`, password: `user` to browse books +- User: `admin`, password: `admin` to manage books and orders + +## Using VS Code + +VS Code supports the project out-of-the-box, when using the [Extension Pack for Java](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack). +To launch the application in VS Code navigate to the `Application` class and click on `Run` or `Debug`. + +## Using Eclipse + +Use the following steps to import the project to Eclipse: + +1. Import the project using **File > Import > Existing Maven Projects**. + + Now, you should see the projects **bookshop** and **bookshop-parent** in the project/package explorer view. + +2. In Project Explorer, change the property "Package Presentation" from "Flat" to "Hierarchical" for better understanding. + +### Building and Running + +1. To **compile** the project, right-click the file `pom.xml` in the `bookshop-parent` project root folder and select +**Run as** > **Maven build**. + + In the following dialog, enter the string `clean install` into the field labeled with "Goals" and click "Run". + + Note: This step also compiles the CDS artifacts, thus repeat this once you made changes to the CDS model. This step also generates source files, therefore refresh the "bookshop" project in your IDE. + +2. To **run** the application, right-click the `bookshop` project root in the Package Explorer and select **Run as** > **Spring Boot App** (make sure you have [Spring Tools 4 installed](https://marketplace.eclipse.org/content/spring-tools-4-aka-spring-tool-suite-4)). + + This step creates a default Run Configuration named `Bookshop - Application` and starts the application afterwards. To go on with the next step, stop the application again. + +3. Then, set the default working directory by editing your Run Configuration via **Run** > **Run Configurations** > **Bookshop - Application**. On the tab **Arguments** change the default **Working Directory** to: + + ```${workspace_loc:bookshop-parent}``` + + Afterward, click **Run**. This step starts the applications `main` method located in `src/main/java/my/bookshop/Application.java`. + +## Using IntelliJ Idea (Community and Ultimate) + +IntelliJ can handle the project more or less out-of-the-box. Since some of the event handlers in the project rely on +the code generated from the CDS model the build path of the project (module) needs to be extended +with the folder containing the generated code. In order to add the generated code you need to add the 'gen' folder +to the build path: + +1. Open the project settings. +2. Navigate to the 'modules' section. +3. Select the srv/src/gen folder and mark it as 'sources'. +4. Save and leave the project settings. +5. Trigger a rebuild. + +After the generated code is considered by IntelliJ's build the application can be handled just as any other Spring Boot +application in IntelliJ. + +## Database Setup and Spring Profiles + +The application comes with two predefined profiles that determine how to run the application: `default`, and `cloud` (see `srv/src/main/resources/application.yaml`). + + +- The `default` profile specifies to use an in-memory H2 database. + The in-memory database is set up automatically during startup of the application and initialized with some example data from CSV files. + +- When deploying the application to Cloud Foundry, the CF Java Buildpack automatically configures the `cloud` Spring profile. + This profile doesn’t specify any datasource location. In that case CAP Java can automatically detect SAP HANA service bindings available in the environment. + +## API_BUSINESS_PARTNER Remote Service and Spring Profiles + +The behavior of the API_BUSINESS_PARTNER remote service is controlled using profiles (see `srv/src/main/resources/application.yaml`): + +- **Using mock data via internal service:** When using only the `default` profile (default when omitting any profile setting), the API_BUSINESS_PARTNER API is mocked as a local service using the mock data. + +- **Using mock data via internal service through OData:** With the `mocked` profile, all requests to the API_BUSINESS_PARTNER service will be routed through HTTP and OData to itself (`http://localhost:/api/API_BUSINESS_PARTNER/...`). This mode is similar to using a real remote destination, and such helps to prevent issues from differences in local service and remote service behavior. + +- **Using the sandbox environment:** You can access data from the [SAP API Business Hub sandbox](https://api.sap.com/api/API_BUSINESS_PARTNER/overview) with the `sandbox` profile. The API key needs to be provided with the environment variable `CDS_REMOTE_SERVICES_API_BUSINESS_PARTNER_HTTP_HEADERS_APIKEY` or in the respective section in [`application.yaml`](srv/src/main/resources/application.yaml). You can retrieve it by clicking on *Show API Key* on [this page](https://api.sap.com/api/API_BUSINESS_PARTNER/overview) after logging in. + +- **Using S/4HANA cloud or on-premise system:** With the `destination` profile, you can access data from a real S/4HANA system. You need to create a destination with name `s4-destination` and make sure that an instance of XSUAA and destination service are bound to your application. For an on-premise destination, you additionally need to bind the connectivity service and add an additional property `URL.headers.sap-client` with the S/4HANA client number to your destination. + +The profiles `sandbox` and `destination` can be combined with the `default` profile for [hybrid testing](https://cap.cloud.sap/docs/advanced/hybrid-testing) and with the `cloud` profile when deployed to the cloud. + +## Deploy to SAP Business Technology Platform, Cloud Foundry + +CAP Java applications can be deployed to the SAP Business Technology Platform either in single tenant or in multitenancy mode. See [Multitenancy in CAP Java](https://cap.cloud.sap/docs/java/multitenancy) for more information. + +Prerequisites: +- Install the [Cloud MTA Build Tool](https://sap.github.io/cloud-mta-build-tool/): `npm install -g mbt`. +- Install the [Cloud Foundry Command Line Interface](https://docs.cloudfoundry.org/cf-cli/install-go-cli.html). +- Get an SAP Business Technology Platform account to deploy the services and applications. +- [Create a SAP HANA Cloud Instance](https://developers.sap.com/tutorials/hana-cloud-deploying.html) in your SAP Business Technology Platform space. +- Ensure you have an entitlement for `SAP HANA Schemas & HDI Containers` with plan `hdi-shared` in the same space. +- Ensure you have provided an API Key for the sandbox environment as described in the previous section. + +> [!NOTE] +> Please note that some IDEs may interfere with their autobuild during the MTA build and thus lead to corrupt MTA build results. Therefore, please ensure that no IDEs are running in parallel with your MTA build. + +Deploy as Single Tenant Application: +- Rename `mta-single-tenant.yaml` to `mta.yaml` +- Run `mbt build` +- Run `cf login` +- Run `cf deploy mta_archives/bookshop_1.0.0.mtar` + +Deploy as Multitenant Application: +- Rename `mta-multi-tenant.yaml` to `mta.yaml` +- Run `mbt build` +- Run `cf login` +- Run `cf deploy mta_archives/bookshop-mt_1.0.0.mtar` +- Go to another subaccount in your global account, under subscriptions and subscribe to the application you deployed. +- Run `cf map-route bookshop-mt-app --hostname ---bookshop-mt-app` or create and bind the route manually. + +> [!NOTE] +> Please note that the route length is limited to 63 characters and can easily be exceeded. So keeping the app name and sub-account subdomain as short as possible will help you stay within length. + +Before you can access the UI using the (tenant-specific) URL to the bookshop(-mt)-app application, make sure to [Setup Authorizations in SAP Business Technology Platform](#setup-authorizations-in-sap-business-technology-platform). + +## Deploy to SAP Business Technology Platform, Kyma Runtime + +**TIP:** You can find more information in the [Deploy Your CAP Application on SAP BTP Kyma Runtime](https://developers.sap.com/mission.btp-deploy-cap-kyma.html) tutorial and in the [Deploy to Kyma/K8s](https://cap.cloud.sap/docs/guides/deployment/deploy-to-kyma) guide of the CAP documentation. + +### Preconditions + +- BTP Subaccount with Kyma Runtime +- BTP Subaccount with Cloud Foundry Space +- [HANA Cloud instance available](https://developers.sap.com/tutorials/hana-cloud-deploying.html) for your Cloud Foundry space +- BTP Entitlements for: *HANA HDI Services & Container* plan *hdi-shared*, *Launchpad Service* plan *standard* +- Container Registry (e.g. [Docker Hub](https://hub.docker.com/)) +- Command Line Tools: [`kubectl`](https://kubernetes.io/de/docs/tasks/tools/install-kubectl/), [`kubectl-oidc_login`](https://github.com/int128/kubelogin#setup), [`pack`](https://buildpacks.io/docs/tools/pack/), [`docker`](https://docs.docker.com/get-docker/), [`helm`](https://helm.sh/docs/intro/install/), [`cf`](https://docs.cloudfoundry.org/cf-cli/install-go-cli.html) +- Logged into Kyma Runtime (with `kubectl` CLI), Cloud Foundry space (with `cf` CLI) and Container Registry (with `docker login`) +- `@sap/cds-dk` >= 6.6.0 + +### Add Deployment Files + +CAP tooling provides you a Helm chart for deployment to Kyma. + +For single tenant deployment, replace the `requires` section in _`.cdsrc.json`_ with: + +``` + "requires": { + "auth": { + "kind": "xsuaa" + }, + "approuter": { + "kind": "cloudfoundry" + }, + "db": { + "kind": "hana-cloud" + } + }, +``` + +**In addition** remove `"profile": "with-mtx-sidecar"` from `.cdsrc.json` and delete the `mtx` folder in root. + +For multi tenant deployment, replace the `requires` section in _`.cdsrc.json`_ with: + +``` + "requires": { + "multitenancy": true, + "extensibility": true, + "toggles": true, + "auth": { + "kind": "xsuaa" + }, + "approuter": { + "kind": "cloudfoundry" + } + }, +``` + +Add the CAP Helm chart with the required features to this project: + +```bash +cds add helm +``` + +#### Use API_BUSSINESS_PARTNER Remote Service (optional, single tenant only) + +You can try the `API_BUSINESS_PARTNER` service with a real S/4HANA system with the following configuration: + +1. Create either an on-premise or cloud destination in your subaccount. + +2. Add configuration required for the destination service by executing the following command. + + ```bash + cds add destination + ``` + +3. Set the profiles `cloud` and `destination` active in your `values.yaml` file: + + ```yaml + srv: + ... + env: + SPRING_PROFILES_ACTIVE: cloud,destination + ``` + +4. For on-premise only: Add the connectivity service to your Helm chart: + + ```bash + cds add connectivity + ``` + + Note: `cds add helm` will not add configuration required to create a Connectivity Service Instance. This Service Instance should be created by the Kyma Cluster Administrator. For more information regarding configuration of Connectivity Instance, please check the [documentation](https://cap.cloud.sap/docs/guides/deployment/deploy-to-kyma#connectivity-service). + +*See also: [API_BUSINESS_PARTNER Remote Service and Spring Profiles](#api_business_partner-remote-service-and-spring-profiles)* + +### Prepare Kubernetes Namespace + +#### Create container registry secret + +Create a secret `container-registry` with credentials to access the container registry: + +``` +bash ./scripts/create-container-registry-secret.sh +``` + +The *Docker Server* is the full qualified hostname of your container registry. + +#### Create a HDI container / Service Manager Instance and a Secret + +This step is only required if you're using a BTP Trial account. If you're using a production or a free tier account then you can create HDI Container from Kyma directly by adding a [mapping to your Kyma namespace in your HANA Cloud Instance](https://blogs.sap.com/2022/12/15/consuming-sap-hana-cloud-from-the-kyma-environment/) and skip this step. + +##### Single Tenant + +``` +bash ./scripts/create-db-secret.sh bookshop-db +``` + +It will create a HDI container `bookshop-db` instance on your currently targeted Cloud Foundry space and a secret `bookshop-db` with the credentials in your current Kubernetes namespace. + +Make the following changes to your _`chart/values.yaml`_. + +```diff +srv: + bindings: + db: +- serviceInstanceName: hana ++ fromSecret: bookshop-db +... + +hana-deployer: + bindings: + hana: +- serviceInstanceName: hana ++ fromSecret: bookshop-db + +... +- hana: +- serviceOfferingName: hana +- servicePlanName: hdi-shared +``` + +Make the following changes to your _`chart/Chart.yaml`_. + +```diff +dependencies: + ... +- - name: service-instance +- alias: hana +- version: ">0.0.0" + ... +``` + +##### Multi Tenant + +``` +bash ./scripts/create-sm-secret.sh bookshop-sm +``` + +It will create a Service Manager `bookshop-sm` instance on your currently targeted Cloud Foundry space and a secret `bookshop-sm` with the credentials in your current Kubernetes namespace. + +Make the following changes to your _`chart/values.yaml`_. + +```diff +srv: + bindings: + service-manager: +- serviceInstanceName: service-manager ++ fromSecret: bookshop-sm +... + +sidecar: + bindings: + service-manager: +- serviceInstanceName: service-manager ++ fromSecret: bookshop-sm + +... +- service-manager: +- serviceOfferingName: service-manager +- servicePlanName: container +``` + +Make the following changes to your _`chart/Chart.yaml`_. + +```diff +dependencies: + ... +- - name: service-instance +- alias: service-manager +- version: ">0.0.0" + ... +``` + +### Build + +```bash +cds build --production +``` + +**Build image for CAP service:** + +```bash +mvn clean package -DskipTests=true +``` + +```bash +pack build ${YOUR_CONTAINER_REGISTRY:?}/bookshop-srv \ + --path srv/target/*-exec.jar \ + --buildpack gcr.io/paketo-buildpacks/sap-machine \ + --buildpack gcr.io/paketo-buildpacks/java \ + --builder paketobuildpacks/builder-jammy-base \ + --env SPRING_PROFILES_ACTIVE=cloud \ + --env BP_JVM_VERSION=17 +``` + +(Replace `${YOUR_CONTAINER_REGISTRY:?}` with the full-qualified hostname of your container registry) + +**Build Approuter Image:** + +```bash +pack build ${YOUR_CONTAINER_REGISTRY:?}/bookshop-approuter \ + --path app \ + --buildpack gcr.io/paketo-buildpacks/nodejs \ + --builder paketobuildpacks/builder-jammy-base \ + --env BP_NODE_RUN_SCRIPTS="" +``` + +**Build database deployer image (single tenant only):** + +```bash +pack build ${YOUR_CONTAINER_REGISTRY:?}/bookshop-hana-deployer \ + --path db \ + --buildpack gcr.io/paketo-buildpacks/nodejs \ + --builder paketobuildpacks/builder-jammy-base \ + --env BP_NODE_RUN_SCRIPTS="" +``` + +**Build sidecar image (multi tenant only):** + +```bash +pack build ${YOUR_CONTAINER_REGISTRY:?}/bookshop-sidecar \ + --path mtx/sidecar/gen \ + --buildpack gcr.io/paketo-buildpacks/nodejs \ + --builder paketobuildpacks/builder-jammy-base \ + --env BP_NODE_RUN_SCRIPTS="" +``` + +### Push container images + +You can push all the container images to your container registry, using: + +```bash +docker push ${YOUR_CONTAINER_REGISTRY:?}/bookshop-srv + +docker push ${YOUR_CONTAINER_REGISTRY:?}/bookshop-approuter +``` + +#### Single Tenant + +```bash +docker push ${YOUR_CONTAINER_REGISTRY:?}/bookshop-hana-deployer +``` + +#### Multi Tenant + +```bash +docker push ${YOUR_CONTAINER_REGISTRY:?}/bookshop-sidecar +``` + +### Configuration + +Make the following changes in the _`chart/values.yaml`_ file. + +1. Change value of `global.domain` key to your cluster domain. + +2. Replace `` in `xsuaa.parameters.oauth2-configuration.redirect-uris` with your cluster domain. + +3. Replace `` with your container registry. + +4. Make the following change to add backend destinations required by Approuter. + +```diff +- backendDestinations: {} ++ backendDestinations: ++ backend: ++ service: srv ++ mtx-api: ++ service: srv +``` + +5. Add your image registry secret created in [Create container registry secret](#create-container-registry-secret) step. + +```diff +global: + domain: null +- imagePullSecret: {} ++ imagePullSecret: ++ name: container-registry +``` + +6. If the application is deployed multiple times in the same cluster, make sure to adapt the values of `xsappname` and `appName` under `saasRegistryParameters` in `values/Chart.yaml` + +### Deployment + +Deploy the helm chart using the following command: + +#### Single Tenant + +```bash +helm install bookshop ./chart --set-file xsuaa.jsonParameters=xs-security.json +``` + +Before you can access the UI you should make sure to [Setup Authorizations in SAP Business Technology Platform](#setup-authorizations-in-sap-business-technology-platform). + +Click on the approuter url logged by the `helm install` to access the UI. + +#### Multi Tenant + +```bash +helm install bookshop ./chart --set-file xsuaa.jsonParameters=xs-security-mt.json +``` + +In case of multi tenant, you'll have to subscribe to the application from a different subaccount. You can follow the steps mentioned [here](https://cap.cloud.sap/docs/guides/deployment/as-saas#subscribe) to access the application. + +## Setup Authorizations in SAP Business Technology Platform + +To access services and UIs that require specific authorizations (e.g. `admin`) you need to assign a corresponding role and role collections to your user in SAP BTP Cockpit. + +1. For single-tenant applications open the subaccount where you deployed the `bookshop` application to. For multitenant applications open the subaccount where you subscribed to the `bookshop` application. +2. Navigate to *Security* -> *Roles* +3. Create a role with name `bookshop-admin` based on the `admin` role template of the `bookshop` application: + 1. Enter a Business Partner ID of your S/4 system as value for the `businessPartner` attribute. When using the sandbox environment use `10401010`. +4. Navigate to *Security* -> *Role Collections* +5. Create a new role collection `bookshop-admin`: + 1. Assign the `bookshop-admin` role to this role collection + 2. Assign the role collection to your user + +# Code Tour + +Take the [guided tour](.tours) in VS Code through our CAP Samples for Java and learn which CAP features are showcased by the different parts of the repository. Just install the [CodeTour extension](https://marketplace.visualstudio.com/items?itemName=vsls-contrib.codetour) for VS Code. + +# Get Support + +In case you have a question, find a bug, or otherwise need support, please use our [community](https://answers.sap.com/tags/9f13aee1-834c-4105-8e43-ee442775e5ce). See the documentation at [https://cap.cloud.sap](https://cap.cloud.sap) for more details about CAP. + +# License + +Copyright (c) 2022 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](LICENSES/Apache-2.0.txt) file. diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/_i18n/i18n.properties b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/_i18n/i18n.properties new file mode 100644 index 000000000..4fa82a6fd --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/_i18n/i18n.properties @@ -0,0 +1,115 @@ +Customer = Customer +CreatedBy = Created By +Date = Date +Created = Created +Modified = Modified +ModifiedBy = Modified By +General = General +Details = Details +Admin = Administrative + +ID = ID +Currency = Currency + +Books = Books +Book = Book +Title = Title +Stock = Stock +Price = Price +Description = Description +BookPrice = Book Price +AddToOrder = Add to Order + +Authors = Authors +Author = Author +AuthorID = Author ID +Name = Name +AuthorName = Author's Name +DateOfBirth = Date of Birth +DateOfDeath = Date of Death +PlaceOfBirth = Place of Birth +PlaceOfDeath = Place of Death + +Order = Order +Orders = Orders +OrderNumber = Order Number +Total = Order Value + +OrderItem = Order Item +OrderItems = Order Items +Quantity = Quantity +Amount = Amount + +ShippingAddress = Shipping Address +ShippingAddresses = Shipping Addresses +CityName = City Name +HouseNumber = House Number +StreetName = Street Name +PostalCode = Postal Code +Country = Country +AddressID = Address ID +BusinessPartner = Contact + +Locale = Language + +Reviews = Reviews +Review = Review +Rating = Rating +Subject = Subject +Date = Date + +User = User +Text = Text +Image = Image +Genres = Genres +Genre = Genre + +AddReview = Add Review + +Notes = Notes +Note = Note +ISBN = ISBN + +reference = Reference +references = References + +#XFLD,50: Label for a section +Chapters=Chapters + +#XFLD,120: Label for entity +Chapter=Chapter + +#XFLD,120: Label for a field +ChapterTitle=Chapter Title + +#XFLD,120: Label for a field +ChapterType=Chapter Type + +#XFLD,50: Label for a section +Pages=Pages + +#XFLD,120: Label for entity +Page=Page + +#XFLD,120: Label for a field +PageTitle=Page Title + +#XFLD,120: Label for a field +PageType=Page Type + +#XFLD,50: Label for a section +Footnotes=Footnotes + +#XFLD,120: Label for a field +Description=Description + +#XFLD,120: Label for a field +URL=URL + +#XFLD,50: Label for a section +GeneralInformation=General Information + +#XFLD,50: Label for a section +Attachments=Attachments +uploadStatus=Upload Status +type=Type \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/_i18n/i18n_de.properties b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/_i18n/i18n_de.properties new file mode 100644 index 000000000..5bb11d0f2 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/_i18n/i18n_de.properties @@ -0,0 +1,71 @@ +Customer = Kunde +CreatedBy = Angelegt von +Date = Datum +Created = Angelegt +Modified = Bearbeitet +ModifiedBy = Bearbeitet von +General = Generelles +Details = Details +Admin = Administratives + +ID = ID +Currency = W\u00E4hrung + +Books = B\u00FCcher +Book = Buch +Title = Titel +Stock = Bestand +Price = Preis +Description = Beschreibung +BookPrice = Buchpreis +AddToOrder = Zu Bestellung hinzuf\u00FCgen + +Authors = Autor +Author = Autor +AuthorID = ID des Autors +Name = Name +AuthorName = Name des Autors +DateOfBirth = Geburtsdatum +DateOfDeath = Sterbedatum +PlaceOfBirth = Geburtsort +PlaceOfDeath = Sterbeort + +Order = Bestellung +Orders = Bestellungen +OrderNumber = Bestellungsnummer +Total = Bestellungswert + +OrderItem = Bestellungseintrag +OrderItems = Bestellungseintr\u00E4ge +Quantity = Menge +Amount = Wert + +ShippingAddress = Lieferaddresse +ShippingAddresses = Lieferaddressen +CityName = Stadt +HouseNumber = Hausnummer +StreetName = Stra\u00DFe +PostalCode = Postleitzahl +Country = Land +AddressID = ID der Addresse +BusinessPartner = Kontakt + +Locale = Sprache + +Reviews = Rezensionen +Review = Rezension +Rating = Bewertung +Subject = Betreff +Date = Datum + +User = Benutzer +Text = Text +Image = Bild +Genres = Genre +Genre = Genre + +AddReview = Rezension hinzufügen + +Notes = Notizen +Note = Notiz +ISBN = ISBN diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/fiori-service.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/fiori-service.cds new file mode 100644 index 000000000..51887f318 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/fiori-service.cds @@ -0,0 +1,83 @@ +using NotesService from '../../srv/notes-mashup'; + +annotate NotesService.Addresses with @(UI : { + LineItem : [ + { + Value : businessPartner, + Label : '{i18n>BusinessPartner}' + }, + { + Value : ID, + Label : '{i18n>ID}' + }, + { + Value : street, + Label : '{i18n>StreetName}' + }, + { + Value : city, + Label : '{i18n>CityName}' + }, + { + Value : country, + Label : '{i18n>Country}' + } + ], + HeaderInfo : { + TypeName : '{i18n>ShippingAddress}', + TypeNamePlural : '{i18n>ShippingAddresses}', + Title : {Value : ID}, + Description : {Value : businessPartner}, + }, + PresentationVariant : { + Text : 'Default', + Visualizations : ['@UI.LineItem'] + }, + Facets : [ + { + $Type : 'UI.ReferenceFacet', + Target : '@UI.FieldGroup#Address', + Label : '{i18n>ShippingAddress}', + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>Notes}', + Target : 'notes/@UI.LineItem' + } + ], + FieldGroup #Address : {Data : [ + { + Value : street, + Label : '{i18n>StreetName}' + }, + { + Value : houseNumber, + Label : '{i18n>HouseNumber}' + }, + { + Value : postalCode, + Label : '{i18n>PostalCode}' + }, + { + Value : city, + Label : '{i18n>CityName}' + }, + { + Value : country, + Label : '{i18n>Country}' + } + ]}, +}) { + businessPartner + @title : '{i18n>BusinessPartner}' + @UI.HiddenFilter; + ID + @title : '{i18n>ID}' + @UI.HiddenFilter; + street + @title : '{i18n>StreetName}'; + city + @title : '{i18n>CityName}'; + country + @title : '{i18n>Country}'; +}; diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/package.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/package.json new file mode 100644 index 000000000..8e75334b8 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/package.json @@ -0,0 +1,12 @@ +{ + "name": "addresses", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/webapp/Component.js b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/webapp/Component.js new file mode 100644 index 000000000..5def6d128 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/webapp/Component.js @@ -0,0 +1,3 @@ +sap.ui.define(["sap/fe/core/AppComponent"], ac => ac.extend("addresses.Component", { + metadata:{ manifest:'json' } +})) diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/webapp/i18n/i18n.properties b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/webapp/i18n/i18n.properties new file mode 100644 index 000000000..32c07eed7 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/webapp/i18n/i18n.properties @@ -0,0 +1,2 @@ +appTitle=Show Shipping Addresses +appDescription=Show Shipping Addresses - Sample Application diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/webapp/i18n/i18n_de.properties b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/webapp/i18n/i18n_de.properties new file mode 100644 index 000000000..a150555b3 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/webapp/i18n/i18n_de.properties @@ -0,0 +1,2 @@ +appTitle=Zeige Lieferaddressen +appDescription=Zeige Lieferaddressen - Beispielanwendung diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/webapp/index.html b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/webapp/index.html new file mode 100644 index 000000000..a59fa7d2c --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/webapp/index.html @@ -0,0 +1,35 @@ + + + + + + + Show Shipping Addresses + + + + +
+ + diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/webapp/manifest.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/webapp/manifest.json new file mode 100644 index 000000000..5266df52f --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/addresses/webapp/manifest.json @@ -0,0 +1,142 @@ +{ + "_version": "1.8.0", + "sap.app": { + "id": "addresses", + "type": "application", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + }, + "dataSources": { + "NotesService": { + "uri": "/api/notes/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + }, + "-sourceTemplate": { + "id": "ui5template.basicSAPUI5ApplicationProject", + "-id": "ui5template.smartTemplate", + "-version": "1.40.12" + }, + "crossNavigation": { + "inbounds": { + "Addresses-show": { + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "semanticObject": "Addresses", + "action": "show" + } + } + } + }, + "sap.ui5": { + "dependencies": { + "libs": { + "sap.fe.templates": {} + } + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "i18n/i18n.properties" + }, + "": { + "dataSource": "NotesService", + "settings": { + "synchronizationMode": "None", + "operationMode": "Server", + "autoExpandSelect" : true, + "earlyRequests": true, + "groupProperties": { + "default": { + "submit": "Auto" + } + } + } + } + }, + "routing": { + "routes": [ + { + "pattern": ":?query:", + "name": "AddressesList", + "target": "AddressesList" + }, + { + "pattern": "Addresses({key}):?query:", + "name": "AddressesDetails", + "target": "AddressesDetails" + }, + { + "pattern": "Addresses({key})/notes({key2}):?query:", + "name": "NotesDetails", + "target": "NotesDetails" + } + ], + "targets": { + "AddressesList": { + "type": "Component", + "id": "AddressesList", + "name": "sap.fe.templates.ListReport", + "options": { + "settings" : { + "entitySet" : "Addresses", + "navigation" : { + "Addresses" : { + "detail" : { + "route" : "AddressesDetails" + } + } + } + } + } + }, + "AddressesDetails": { + "type": "Component", + "id": "AddressesDetails", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet" : "Addresses", + "navigation" : { + "notes" : { + "detail" : { + "route" : "NotesDetails" + } + } + } + } + } + }, + "NotesDetails": { + "type": "Component", + "id": "NotesDetails", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet": "Notes" + } + } + } + } + }, + "contentDensities": { + "compact": true, + "cozy": true + } + }, + "sap.ui": { + "technology": "UI5", + "fullWidth": false + }, + "sap.fiori": { + "registrationIds": [], + "archeType": "transactional" + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/fiori-service.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/fiori-service.cds new file mode 100644 index 000000000..8dd68120a --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/fiori-service.cds @@ -0,0 +1,401 @@ +/* + Annotations for the Manage Books App +*/ + +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>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' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'AttachmentsFacet', + Label : '{i18n>attachments}', + Target : 'attachments/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'ReferencesFacet', + Label : 'References', + Target : 'references/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'FootNotesFacet', + Label : 'FootNotes', + Target : 'footnotes/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>Chapters}', + ID : 'i18nChapters', + Target : 'cHapters/@UI.LineItem#i18nChapters', + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>Pages}', + ID : 'i18nPages', + Target : 'pages/@UI.LineItem#i18nPages', + }, + ], + 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 my.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 + } +} + +annotate AdminService.Books actions { + @( + Common.SideEffects : { + TargetProperties : ['_it/order_ID'], + TargetEntities : [_it] + }, + cds.odata.bindingparameter.name : '_it' + ) + addToOrder(order_ID @( + title : '{i18n>Order}', + Common : {ValueListMapping : { + Label : '{i18n>Orders}', + CollectionPath : 'Orders', + Parameters : [ + { + $Type : 'Common.ValueListParameterInOut', + LocalDataProperty : order_ID, + ValueListProperty : 'ID' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'OrderNo' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'createdBy' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'createdAt' + } + ], + }} + ), + quantity @title : '{i18n>Quantity}' + ) +} + +annotate AdminService.Books.attachments with { + customProperty1 @Common.ValueListWithFixedValues; +} +annotate AdminService.Books.references with { + customProperty1 @Common.ValueListWithFixedValues; +} +annotate AdminService.Books.footnotes with { + customProperty1 @Common.ValueListWithFixedValues; +} + +// Chapters annotations +annotate AdminService.Chapters with @title : '{i18n>Chapter}'; + +annotate AdminService.Books.chapters with @( + title : '{i18n>Chapters}' +); + +annotate AdminService.Chapters with @( + UI.LineItem : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>ChapterTitle}', + }, + { + $Type : 'UI.DataField', + Value : chapterType, + Label : '{i18n>ChapterType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + ], + UI.LineItem #i18nChapters : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>ChapterTitle}', + }, + { + $Type : 'UI.DataField', + Value : chapterType, + Label : '{i18n>ChapterType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + ] +); + +annotate AdminService.Chapters with @( + UI.HeaderInfo : { + Title : { + $Type : 'UI.DataField', + Value : title, + }, + TypeName : '{i18n>Chapter}', + TypeNamePlural : '{i18n>Chapters}', + Description : { + $Type : 'UI.DataField', + Value : description, + }, + } +); + +annotate AdminService.Chapters with @( + UI.FieldGroup #GeneratedGroup1 : { + $Type : 'UI.FieldGroupType', + Data : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>ChapterTitle}', + }, + { + $Type : 'UI.DataField', + Value : chapterType, + Label : '{i18n>ChapterType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + { + $Type : 'UI.DataField', + Value : url, + Label : '{i18n>URL}', + }, + ], + }, + UI.Facets : [ + { + $Type : 'UI.ReferenceFacet', + ID : 'GeneratedFacet1', + Label : '{i18n>GeneralInformation}', + Target : '@UI.FieldGroup#GeneratedGroup1', + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'AttachmentsFacet', + Label : '{i18n>attachments}', + Target : 'attachments/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'ReferencesFacet', + Label : '{i18n>references}', + Target : 'references/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'FootnotesFacet', + Label : '{i18n>Footnotes}', + Target : 'footnotes/@UI.LineItem' + } + ] +); + +////////// + +// Pages annotations +annotate AdminService.Pages with @title : '{i18n>Page}'; + +annotate AdminService.Books.pages with @( + title : '{i18n>Pages}' +); + +annotate AdminService.Pages with @( + UI.LineItem : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>PageTitle}', + }, + { + $Type : 'UI.DataField', + Value : pageType, + Label : '{i18n>PageType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + ], + UI.LineItem #i18nPages : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>PageTitle}', + }, + { + $Type : 'UI.DataField', + Value : pageType, + Label : '{i18n>PageType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + ] +); + +annotate AdminService.Pages with @( + UI.HeaderInfo : { + Title : { + $Type : 'UI.DataField', + Value : title, + }, + TypeName : '{i18n>Page}', + TypeNamePlural : '{i18n>Pages}', + Description : { + $Type : 'UI.DataField', + Value : description, + }, + } +); + +annotate AdminService.Pages with @( + UI.FieldGroup #GeneratedGroup1 : { + $Type : 'UI.FieldGroupType', + Data : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>PageTitle}', + }, + { + $Type : 'UI.DataField', + Value : pageType, + Label : '{i18n>PageType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + { + $Type : 'UI.DataField', + Value : url, + Label : '{i18n>URL}', + }, + ], + }, + UI.Facets : [ + { + $Type : 'UI.ReferenceFacet', + ID : 'GeneratedFacet1', + Label : '{i18n>GeneralInformation}', + Target : '@UI.FieldGroup#GeneratedGroup1', + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'AttachmentsFacet', + Label : '{i18n>attachments}', + Target : 'attachments/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'ReferencesFacet', + Label : '{i18n>references}', + Target : 'references/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'FootnotesFacet', + Label : '{i18n>Footnotes}', + Target : 'footnotes/@UI.LineItem' + } + ] +); \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/package.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/package.json new file mode 100644 index 000000000..17db44b07 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/package.json @@ -0,0 +1,12 @@ +{ + "name": "admin", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/Component.js b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/Component.js new file mode 100644 index 000000000..332ed12eb --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/Component.js @@ -0,0 +1,3 @@ +sap.ui.define(["sap/fe/core/AppComponent"], ac => ac.extend("admin.Component", { + metadata:{ manifest:'json' } +})) diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/books/controller/custom.controller.js b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/books/controller/custom.controller.js new file mode 100644 index 000000000..a7fd5a2a7 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/books/controller/custom.controller.js @@ -0,0 +1,33 @@ +sap.ui.define( + [ + "sap/ui/core/mvc/ControllerExtension", + "sap/m/library" + ], + function (ControllerExtension,library) { + "use strict"; + + return ControllerExtension.extend("books.controller.custom", { + onRowPress: function(oContext) { + this.base.editFlow + .invokeAction("AdminService.openAttachment", { + contexts: oContext.getParameter("bindingContext") + }) + .then(function (res) { + let odataurl = ""; + if(res.getObject().value == "None") { + const lastSlashIndex = res.oModel.getServiceUrl().lastIndexOf('/'); + let str = res.oModel.getServiceUrl(); + if (lastSlashIndex !== -1) { + str = str.substring(0, lastSlashIndex) + str.substring(lastSlashIndex + 1); + } + odataurl = str+res.oBinding.oContext.sPath+"/content"; + } else { + odataurl = res.getObject().value; + } + library.URLHelper.redirect(odataurl, true); + + }); + } + }); + } +); \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/controller/custom.controller.js b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/controller/custom.controller.js new file mode 100644 index 000000000..9b02ce0c3 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/controller/custom.controller.js @@ -0,0 +1,141 @@ +sap.ui.define( + [ + "sap/ui/core/mvc/ControllerExtension", + "sap/m/library", + "sap/ui/core/format/DateFormat" + ], + function (ControllerExtension,library, DateFormat) { + "use strict"; + const ChangeCategoryEnum = { + created: "Created", + updated: "Changed" + // Add more mappings as needed + }; + + return ControllerExtension.extend("admin.controller.custom", { + isDownloadEnabled: function(oBindingContext, aSelectedContexts) { + if (!aSelectedContexts || aSelectedContexts.length === 0) { + return false; + } + return !aSelectedContexts.some(function(oContext) { + return oContext.getProperty("mimeType") === "application/internet-shortcut"; + }); + }, + onRowPress: function(oContext) { + this.base.editFlow + .invokeAction("AdminService.openAttachment", { + contexts: oContext.getParameter("bindingContext") + }) + .then(function (res) { + let odataurl = ""; + if(res.getObject().value == "None") { + const lastSlashIndex = res.oModel.getServiceUrl().lastIndexOf('/'); + let str = res.oModel.getServiceUrl(); + if (lastSlashIndex !== -1) { + str = str.substring(0, lastSlashIndex) + str.substring(lastSlashIndex + 1); + } + odataurl = str+res.oBinding.oContext.sPath+"/content"; + } else { + odataurl = res.getObject().value; + } + library.URLHelper.redirect(odataurl, true); + + }); + }, + onChangelogPress: function(oContext, aSelectedContexts) { + var that =this; + this.base.editFlow + .invokeAction("AdminService.changelog", { + contexts: aSelectedContexts + }) + .then(function (res) { + console.log("Result",res[0].value.getObject().value); + that.updateChangeLogInPropertiesModel(res[0].value.getObject().value); + }); + }, + updateChangeLogInPropertiesModel: function (oChangeLogsForObjectResponse) { + const aChangeLogs = []; + const fileName = JSON.parse(oChangeLogsForObjectResponse).filename; + console.log("Filename: ", fileName); + const aChangeLogsObject = JSON.parse(oChangeLogsForObjectResponse)["changeLogs"]; + console.log("ChangeLogsObject:\n", aChangeLogsObject); + // Take latest changes at the top + for (let idx = aChangeLogsObject.length - 1; idx >= 0; idx--) { + const oChangeLogEntry = aChangeLogsObject[idx]; + const sLastModifiedBy = oChangeLogEntry["user"]; + const sChangeType = oChangeLogEntry["operation"]; + const sChangeTime = oChangeLogEntry["time"]; + let dateTimeFormat = DateFormat.getDateTimeInstance(sap.ui.getCore().getConfiguration().getLocale()); + let changedDate = new Date(sChangeTime); + let changedTime = changedDate?dateTimeFormat.format(new Date(changedDate)) : "" ; + const oChangeLog = { + changedOn: changedTime, + changedBy: sLastModifiedBy, + changeType: ChangeCategoryEnum[sChangeType] + }; + aChangeLogs.push(oChangeLog); + console.log("ChangeLog:\n", oChangeLog); + } + + this.logFragment= this.base.getExtensionAPI().loadFragment({ + name: "admin.fragments.changelog", + controller: this + }); + var that = this; + this.logFragment.then(function (dialog) { + if(dialog){ + dialog.attachEventOnce("afterClose", function () { + dialog.destroy(); + }); + var oModel = new sap.ui.model.json.JSONModel(); + oModel.setSizeLimit(100000); + oModel.setData(aChangeLogs); + that.getView().setModel(oModel, "changelog"); + dialog.setTitle(fileName); + dialog.open() + } + }); + }, + close: function (closeBtn) { + closeBtn.getSource().getParent().close(); + }, + onDownloadPress: function(oContext, aSelectedContexts) { + var sIds = aSelectedContexts.map(function (oCtx) { + return oCtx.getObject().ID; + }).join(","); + this.base.editFlow + .invokeAction("AdminService.downloadSelectedAttachments", { + contexts: aSelectedContexts[0], + parameterValues: [{ name: "ids", value: sIds }], + skipParameterDialog: true + }) + .then(function (res) { + var sJsonResponse = res.getObject().value; + var aEntries = JSON.parse(sJsonResponse); + aEntries.forEach(function (oEntry) { + if (oEntry.status === "success") { + if (oEntry.linkUrl) { + window.open(oEntry.linkUrl, "_blank"); + } else if (oEntry.content) { + var byteString = atob(oEntry.content); + var aBytes = new Uint8Array(byteString.length); + for (var i = 0; i < byteString.length; i++) { + aBytes[i] = byteString.charCodeAt(i); + } + var oBlob = new Blob([aBytes], { type: oEntry.mimeType || "application/octet-stream" }); + var sUrl = URL.createObjectURL(oBlob); + var oLink = document.createElement("a"); + oLink.href = sUrl; + oLink.download = oEntry.fileName || "download"; + document.body.appendChild(oLink); + oLink.click(); + document.body.removeChild(oLink); + URL.revokeObjectURL(sUrl); + } + } + }); + }); + } + }); + } +); diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/extension/Upload.js b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/extension/Upload.js new file mode 100644 index 000000000..bc1ce3d52 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/extension/Upload.js @@ -0,0 +1,119 @@ +sap.ui.define( + ["sap/m/MessageBox", "sap/m/MessageToast"], + function (MessageBox, MessageToast) { + "use strict"; + + function _createUploadController(oExtensionAPI) { + var oUploadDialog; + + function setOkButtonEnabled(bOk) { + oUploadDialog && oUploadDialog.getBeginButton().setEnabled(bOk); + } + + function setDialogBusy(bBusy) { + oUploadDialog.setBusy(bBusy) + } + + function closeDialog() { + oUploadDialog && oUploadDialog.close() + } + + function showError(sMessage) { + MessageBox.error(sMessage || "Upload failed") + } + + // TODO: Better option for this? + function byId(sId) { + return sap.ui.core.Fragment.byId("uploadDialog", sId); + } + + return { + onBeforeOpen: function (oEvent) { + oUploadDialog = oEvent.getSource(); + oExtensionAPI.addDependent(oUploadDialog); + }, + + onAfterClose: function (oEvent) { + oExtensionAPI.removeDependent(oUploadDialog); + oUploadDialog.destroy(); + oUploadDialog = undefined; + }, + + onOk: function (oEvent) { + setDialogBusy(true) + + var oFileUploader = byId("uploader") + + oFileUploader + .checkFileReadable() + .then(function () { + oFileUploader.upload(); + }) + .catch(function (error) { + showError("The file cannot be read."); + setDialogBusy(false) + }) + }, + + onCancel: function (oEvent) { + closeDialog(); + }, + + onTypeMismatch: function (oEvent) { + var sSupportedFileTypes = oEvent + .getSource() + .getFileType() + .map(function (sFileType) { + return "*." + sFileType; + }) + .join(", "); + + showError( + "The file type *." + + oEvent.getParameter("fileType") + + " is not supported. Choose one of the following types: " + + sSupportedFileTypes + ); + }, + + onFileAllowed: function (oEvent) { + setOkButtonEnabled(true) + }, + + onFileEmpty: function (oEvent) { + setOkButtonEnabled(false) + }, + + onUploadComplete: function (oEvent) { + var iStatus = oEvent.getParameter("status"); + var oFileUploader = oEvent.getSource() + + oFileUploader.clear(); + setOkButtonEnabled(false) + setDialogBusy(false) + + if (iStatus >= 400) { + var oRawResponse = JSON.parse(oEvent.getParameter("responseRaw")); + showError(oRawResponse && oRawResponse.error && oRawResponse.error.message); + } else { + MessageToast.show("Uploaded successfully"); + oExtensionAPI.refresh() + closeDialog(); + } + } + }; + } + + return { + showUploadDialog: function (oBindingContext, aSelectedContexts) { + this.loadFragment({ + id: "uploadDialog", + name: "admin.extension.UploadDialog", + controller: _createUploadController(this) + }).then(function (oDialog) { + oDialog.open(); + }); + } + }; + } +); \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/extension/UploadDialog.fragment.xml b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/extension/UploadDialog.fragment.xml new file mode 100644 index 000000000..4edaded54 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/extension/UploadDialog.fragment.xml @@ -0,0 +1,27 @@ + + + + + + + + \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/fragments/changelog.fragment.xml b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/fragments/changelog.fragment.xml new file mode 100644 index 000000000..1a1462526 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/fragments/changelog.fragment.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+ + +
+
\ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/i18n/i18n.properties b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/i18n/i18n.properties new file mode 100644 index 000000000..6615b898c --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/i18n/i18n.properties @@ -0,0 +1,2 @@ +appTitle=Manage Books +appDescription=Manage Books - Sample Application diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/i18n/i18n_de.properties b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/i18n/i18n_de.properties new file mode 100644 index 000000000..69ef58862 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/i18n/i18n_de.properties @@ -0,0 +1,2 @@ +appTitle=Administriere B\u00FCcher +appDescription=Administriere B\u00FCcher - Beispielanwendung diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/index.html b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/index.html new file mode 100644 index 000000000..4a5cae947 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/index.html @@ -0,0 +1,35 @@ + + + + + + + Manage Books + + + + +
+ + diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/manifest.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/manifest.json new file mode 100644 index 000000000..938a69c16 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/admin/webapp/manifest.json @@ -0,0 +1,487 @@ +{ + "_version": "1.8.0", + "sap.app": { + "id": "admin", + "type": "application", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + }, + "dataSources": { + "AdminService": { + "uri": "/api/admin/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + }, + "-sourceTemplate": { + "id": "ui5template.basicSAPUI5ApplicationProject", + "-id": "ui5template.smartTemplate", + "-version": "1.40.12" + }, + "crossNavigation": { + "inbounds": { + "Books-manage": { + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "semanticObject": "Books", + "action": "manage" + } + } + } + }, + "sap.ui5": { + "dependencies": { + "libs": { + "sap.fe.templates": {} + } + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "i18n/i18n.properties" + }, + "": { + "dataSource": "AdminService", + "settings": { + "synchronizationMode": "None", + "operationMode": "Server", + "autoExpandSelect": true, + "earlyRequests": true, + "groupProperties": { + "default": { + "submit": "Auto" + } + } + } + } + }, + "routing": { + "routes": [ + { + "pattern": ":?query:", + "name": "BooksList", + "target": "BooksList" + }, + { + "pattern": "Books({key}):?query:", + "name": "BooksDetails", + "target": "BooksDetails" + }, + { + "pattern": "Books({key})/author({key2}):?query:", + "name": "AuthorsDetails", + "target": "AuthorsDetails" + }, + { + "pattern": "Books({key})/cHapters({key2}):?query:", + "name": "ChaptersObjectPage", + "target": "ChaptersObjectPage" + }, + { + "pattern": "Books({key})/pages({key2}):?query:", + "name": "PagesObjectPage", + "target": "PagesObjectPage" + } + ], + "targets": { + "BooksList": { + "type": "Component", + "id": "BooksList", + "name": "sap.fe.templates.ListReport", + "options": { + "settings": { + "entitySet": "Books", + "navigation": { + "Books": { + "detail": { + "route": "BooksDetails" + } + }, + "Chapters": { + "detail": { + "route": "ChaptersObjectPage" + } + }, + "Pages": { + "detail": { + "route": "PagesObjectPage" + } + } + }, + "content": { + "header": { + "actions": { + "upload": { + "press": "admin.extension.Upload.showUploadDialog", + "text": "Import Books" + } + } + } + } + } + } + }, + "BooksDetails": { + "type": "Component", + "id": "BooksDetailsList", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings": { + "entitySet": "Books", + "navigation": { + "Authors": { + "detail": { + "route": "AuthorsDetails" + } + }, + "Chapters": { + "detail": { + "route": "ChaptersObjectPage" + } + }, + "Pages": { + "detail": { + "route": "PagesObjectPage" + } + } + }, + "controlConfiguration": { + "attachments/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.admin.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.admin.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.admin.controller.custom.isDownloadEnabled", + "press": ".extension.admin.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "references/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.admin.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.admin.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.admin.controller.custom.isDownloadEnabled", + "press": ".extension.admin.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "footnotes/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.admin.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.admin.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.admin.controller.custom.isDownloadEnabled", + "press": ".extension.admin.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + } + } + } + } + }, + "AuthorsDetails": { + "type": "Component", + "id": "AuthorsDetailsList", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings": { + "entitySet": "Authors" + } + } + }, + "ChaptersObjectPage": { + "type": "Component", + "id": "ChaptersObjectPage", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings": { + "editableHeaderContent": false, + "entitySet": "Chapters", + "controlConfiguration": { + "attachments/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.admin.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.admin.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.admin.controller.custom.isDownloadEnabled", + "press": ".extension.admin.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "references/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.admin.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.admin.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.admin.controller.custom.isDownloadEnabled", + "press": ".extension.admin.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "footnotes/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.admin.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.admin.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.admin.controller.custom.isDownloadEnabled", + "press": ".extension.admin.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + } + } + } + } + }, + "PagesObjectPage": { + "type": "Component", + "id": "PagesObjectPage", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings": { + "editableHeaderContent": false, + "entitySet": "Pages", + "navigation": {}, + "controlConfiguration": { + "attachments/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.admin.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.admin.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.admin.controller.custom.isDownloadEnabled", + "press": ".extension.admin.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "references/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.admin.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.admin.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.admin.controller.custom.isDownloadEnabled", + "press": ".extension.admin.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "footnotes/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.admin.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.admin.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.admin.controller.custom.isDownloadEnabled", + "press": ".extension.admin.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + } + } + } + } + } + } + }, + "extends": { + "extensions": { + "sap.ui.controllerExtensions": { + "sap.fe.templates.ObjectPage.ObjectPageController#admin::BooksDetailsList": { + "controllerName": "admin.controller.custom" + }, + "sap.fe.templates.ObjectPage.ObjectPageController#admin::ChaptersObjectPage": { + "controllerName": "admin.controller.custom" + }, + "sap.fe.templates.ObjectPage.ObjectPageController#admin::PagesObjectPage": { + "controllerName": "admin.controller.custom" + } + } + } + }, + "contentDensities": { + "compact": true, + "cozy": true + } + }, + "sap.ui": { + "technology": "UI5", + "fullWidth": false + }, + "sap.fiori": { + "registrationIds": [], + "archeType": "transactional" + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/appconfig/fioriSandboxConfig.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/appconfig/fioriSandboxConfig.json new file mode 100644 index 000000000..1dc45ef87 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/appconfig/fioriSandboxConfig.json @@ -0,0 +1,185 @@ +{ + "services": { + "LaunchPage": { + "adapter": { + "config": { + "catalogs": [], + "groups": [ + { + "id": "Bookshop", + "title": "Bookshop", + "isPreset": true, + "isVisible": true, + "isGroupLocked": false, + "tiles": [ + { + "id": "browse-books", + "tileType": "sap.ushell.ui.tile.StaticTile", + "properties": { + "targetURL": "#Books-display", + "title": "Browse Books", + "description": "Find your favorite book" + } + } + ] + }, + { + "id": "Administration", + "title": "Administration", + "isPreset": true, + "isVisible": true, + "isGroupLocked": false, + "tiles": [ + { + "id": "manage-books", + "tileType": "sap.ushell.ui.tile.StaticTile", + "properties": { + "targetURL": "#Books-manage", + "title": "Manage Books", + "description": "Add/edit/delete books" + } + }, + { + "id": "manage-orders", + "tileType": "sap.ushell.ui.tile.StaticTile", + "properties": { + "targetURL": "#Orders-manage", + "title": "Manage Orders", + "description": "Find & manage orders" + } + }, + { + "id": "manage-reviews", + "tileType": "sap.ushell.ui.tile.StaticTile", + "properties": { + "targetURL": "#Reviews-manage", + "title": "Manage Reviews", + "description": "Add/edit/delete reviews" + } + } + ] + }, + { + "id": "Shipping", + "title": "Shipping", + "isPreset": true, + "isVisible": true, + "isGroupLocked": false, + "tiles": [ + { + "id": "manage-notes", + "tileType": "sap.ushell.ui.tile.StaticTile", + "properties": { + "targetURL": "#Notes-manage", + "title": "Manage Notes", + "description": "Read & create notes for addresses" + } + }, + { + "id": "show-addresses", + "tileType": "sap.ushell.ui.tile.StaticTile", + "properties": { + "targetURL": "#Addresses-display", + "title": "Show Shipping Addresses", + "description": "Find the right shipping address" + } + } + ] + } + ] + } + } + }, + "NavTargetResolution": { + "config": { + "enableClientSideTargetResolution": true + } + }, + "ClientSideTargetResolution": { + "adapter": { + "config": { + "inbounds": { + "browse-books": { + "semanticObject": "Books", + "action": "display", + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "resolutionResult": { + "applicationType": "SAPUI5", + "additionalInformation": "SAPUI5.Component=bookshop", + "url": "/browse/webapp" + } + }, + "manage-books": { + "semanticObject": "Books", + "action": "manage", + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "resolutionResult": { + "applicationType": "SAPUI5", + "additionalInformation": "SAPUI5.Component=admin", + "url": "/admin/webapp" + } + }, + "manage-orders": { + "semanticObject": "Orders", + "action": "manage", + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "resolutionResult": { + "applicationType": "SAPUI5", + "additionalInformation": "SAPUI5.Component=orders", + "url": "/orders/webapp" + } + }, + "manage-reviews": { + "semanticObject": "Reviews", + "action": "manage", + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "resolutionResult": { + "applicationType": "SAPUI5", + "additionalInformation": "SAPUI5.Component=reviews", + "url": "/reviews/webapp" + } + }, + "manage-notes": { + "semanticObject": "Notes", + "action": "manage", + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "resolutionResult": { + "applicationType": "SAPUI5", + "additionalInformation": "SAPUI5.Component=notes", + "url": "/notes/webapp" + } + }, + "show-addresses": { + "semanticObject": "Addresses", + "action": "display", + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "resolutionResult": { + "applicationType": "SAPUI5", + "additionalInformation": "SAPUI5.Component=addresses", + "url": "/addresses/webapp" + } + } + } + } + } + } + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/fiori-service.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/fiori-service.cds new file mode 100644 index 000000000..953c39dc2 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/fiori-service.cds @@ -0,0 +1,177 @@ +/* + Annotations for the Browse Books App +*/ + +using CatalogService from '../../srv/cat-service'; + +//////////////////////////////////////////////////////////////////////////// +// +// Books Object Page +// +annotate CatalogService.Books with @(UI : { + HeaderInfo : { + TypeName : '{i18n>Book}', + TypeNamePlural : '{i18n>Books}', + Title : {Value : title}, + Description : {Value : author.name} + }, + Identification : [ + {Value : title}, + { + $Type : 'UI.DataFieldForAction', + Label : '{i18n>AddReview}', + Action : 'CatalogService.addReview' + } + ], + PresentationVariant : { + Text : 'Default', + SortOrder : [{Property : title}], + Visualizations : ['@UI.LineItem'] + }, + SelectionFields : [ + author_ID, + genre_ID + ], + HeaderFacets : [ + { + $Type : 'UI.ReferenceFacet', + Target : '@UI.DataPoint#rating' + }, + { + $Type : 'UI.ReferenceFacet', + Target : '@UI.DataPoint#price' + } + ], + LineItem : [ + {Value : title}, + { + Value : author.name, + Label : '{i18n>Author}' + }, + { + Value : genre.name, + Label : '{i18n>Genre}' + }, + { + $Type : 'UI.DataFieldForAnnotation', + Target : '@UI.DataPoint#rating', + Label : '{i18n>Rating}' + }, + {Value : price}, + { + $Type : 'UI.DataFieldForAnnotation', + Label : '{i18n>AddReview}', + Target : '@UI.FieldGroup#AddReview' + } + ], + Facets : [ + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>General}', + Target : '@UI.FieldGroup#General' + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>Description}', + Target : '@UI.FieldGroup#Descr' + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>Reviews}', + Target : 'reviews/@UI.LineItem' + } + ], + FieldGroup #AddReview : {Data : [{ + $Type : 'UI.DataFieldForAction', + Label : '{i18n>AddReview}', + Action : 'CatalogService.addReview', + InvocationGrouping : #ChangeSet + }, ]}, + FieldGroup #General : {Data : [ + {Value : title}, + {Value : author_ID}, + {Value : genre_ID} + ]}, + FieldGroup #Descr : {Data : [{Value : descr}]}, + DataPoint #stock : { + Value : stock, + Title : '{i18n>Stock}' + }, + DataPoint #price : { + Value : price, + Title : '{i18n>Price}' + }, + DataPoint #rating : { + Value : rating, + Title : '{i18n>Rating}', + Visualization : #Rating, + MinimumValue : 0, + MaximumValue : 5, + TargetValue : 5 + } +}) { + @Measures.ISOCurrency : currency_code + price +}; + +annotate CatalogService.Books.texts with @(UI : {LineItem : [ + {Value : locale}, + {Value : title}, + {Value : descr} +]}); + +annotate CatalogService.Reviews with @(UI : { + PresentationVariant : { + $Type : 'UI.PresentationVariantType', + SortOrder : [{ + $Type : 'Common.SortOrderType', + Property : modifiedAt, + Descending : true + }, ], + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAnnotation', + Label : '{i18n>Rating}', + Target : '@UI.DataPoint#rating' + }, + { + $Type : 'UI.DataFieldForAnnotation', + Label : '{i18n>User}', + Target : '@UI.FieldGroup#ReviewerAndDate' + }, + { + Value : title, + Label : '{i18n>Title}' + }, + { + Value : text, + Label : '{i18n>Text}' + }, + ], + DataPoint #rating : { + Value : rating, + Visualization : #Rating, + MinimumValue : 0, + MaximumValue : 5 + }, + FieldGroup #ReviewerAndDate : {Data : [ + {Value : createdBy}, + {Value : modifiedAt} + ]} +}); + +annotate CatalogService.Books actions { + @( + Common.SideEffects : { + TargetProperties : ['_it/rating'], + TargetEntities : [ + _it, + _it.reviews + ] + }, + cds.odata.bindingparameter.name : '_it', + Core.OperationAvailable : _it.isReviewable + ) + addReview(rating @title : '{i18n>Rating}', title @title : '{i18n>Title}', text @title : '{i18n>Text}') +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/package.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/package.json new file mode 100644 index 000000000..81d3bd886 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/package.json @@ -0,0 +1,12 @@ +{ + "name": "browse", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/webapp/Component.js b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/webapp/Component.js new file mode 100644 index 000000000..153759efb --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/webapp/Component.js @@ -0,0 +1,3 @@ +sap.ui.define(["sap/fe/core/AppComponent"], ac => ac.extend("bookshop.Component", { + metadata:{ manifest:'json' } +})) diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/webapp/i18n/i18n.properties b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/webapp/i18n/i18n.properties new file mode 100644 index 000000000..fbeb70f50 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/webapp/i18n/i18n.properties @@ -0,0 +1,2 @@ +appTitle=Browse Books +appDescription=Browse Books - Sample Application diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/webapp/i18n/i18n_de.properties b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/webapp/i18n/i18n_de.properties new file mode 100644 index 000000000..2d2581255 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/webapp/i18n/i18n_de.properties @@ -0,0 +1,2 @@ +appTitle=Zeige B\u00FCcher +appDescription=Zeige B\u00FCcher - Beispielanwendung diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/webapp/index.html b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/webapp/index.html new file mode 100644 index 000000000..99f40f32b --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/webapp/index.html @@ -0,0 +1,35 @@ + + + + + + + Browse Books + + + + +
+ + diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/webapp/manifest.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/webapp/manifest.json new file mode 100644 index 000000000..ec7a8840f --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/browse/webapp/manifest.json @@ -0,0 +1,142 @@ +{ + "_version": "1.8.0", + "sap.app": { + "id": "bookshop", + "type": "application", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + }, + "dataSources": { + "CatalogService": { + "uri": "/api/browse/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + }, + "-sourceTemplate": { + "id": "ui5template.basicSAPUI5ApplicationProject", + "-id": "ui5template.smartTemplate", + "-version": "1.40.12" + }, + "crossNavigation": { + "inbounds": { + "Books-show": { + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "semanticObject": "Books", + "action": "show" + } + } + } + }, + "sap.ui5": { + "dependencies": { + "libs": { + "sap.fe.templates": {} + } + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "i18n/i18n.properties" + }, + "": { + "dataSource": "CatalogService", + "settings": { + "synchronizationMode": "None", + "operationMode": "Server", + "autoExpandSelect" : true, + "earlyRequests": true, + "groupProperties": { + "default": { + "submit": "Auto" + } + } + } + } + }, + "routing": { + "routes": [ + { + "pattern": ":?query:", + "name": "BooksList", + "target": "BooksList" + }, + { + "pattern": "Books({key}):?query:", + "name": "BooksDetails", + "target": "BooksDetails" + }, + { + "pattern": "Books({key}/author({key2}):?query:", + "name": "AuthorsDetails", + "target": "AuthorsDetails" + } + ], + "targets": { + "BooksList": { + "type": "Component", + "id": "BooksList", + "name": "sap.fe.templates.ListReport", + "options": { + "settings" : { + "entitySet" : "Books", + "navigation" : { + "Books" : { + "detail" : { + "route" : "BooksDetails" + } + } + } + } + } + }, + "BooksDetails": { + "type": "Component", + "id": "BooksDetailsList", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet" : "Books", + "navigation" : { + "Authors" : { + "detail" : { + "route" : "AuthorsDetails" + } + } + } + } + } + }, + "AuthorsDetails": { + "type": "Component", + "id": "AuthorsDetailsList", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet" : "Authors" + } + } + } + } + }, + "contentDensities": { + "compact": true, + "cozy": true + } + }, + "sap.ui": { + "technology": "UI5", + "fullWidth": false + }, + "sap.fiori": { + "registrationIds": [], + "archeType": "transactional" + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/common.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/common.cds new file mode 100644 index 000000000..c5f121214 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/common.cds @@ -0,0 +1,1193 @@ +/* + Common Annotations shared by all apps +*/ +using {my.bookshop as my} from '../db/index'; +using {sap.common as common} from '@sap/cds/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 : ' ' + }, + { + $Type : 'UI.DataFieldForAction', + Label : '{i18n>AddToOrder}', + Action : 'AdminService.addToOrder' + }, + ] + } +) { + author + @ValueList.entity : 'Authors'; +}; + + +//////////////////////////////////////////////////////////////////////////// +// +// Books Details +// +annotate my.Books with +@(UI : {HeaderInfo : { + TypeName : '{i18n>Book}', + TypeNamePlural : '{i18n>Books}', + TypeImageUrl : 'sap-icon://course-book', + Title : {Value : title}, + Description : {Value : author.name} +}, }); + +//////////////////////////////////////////////////////////////////////////// +// +// Attachments Details +// + +annotate my.Books.attachments with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Attachment}', + TypeNamePlural: '{i18n>Attachments}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Attachments', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink', + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + type @(title: '{i18n>Type}'); + linkUrl @UI.Hidden; + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} +annotate Attachments with @Common: {SideEffects #ContentChanged: { + SourceProperties: [content], + TargetProperties: ['status'], + TargetEntities : [Books.attachments] +}}{}; + +annotate my.Books.references with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Attachment}', + TypeNamePlural: '{i18n>Attachments}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Attachments', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink', + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} { + note @(title: '{i18n>Note}'); + type @(title: '{i18n>Type}'); + linkUrl @UI.Hidden; + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Books.footnotes with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Attachment}', + TypeNamePlural: '{i18n>Attachments}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Attachments', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink', + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} { + note @(title: '{i18n>Note}'); + type @(title: '{i18n>Type}'); + linkUrl @UI.Hidden; + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Chapters.attachments with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Attachment}', + TypeNamePlural: '{i18n>Attachments}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Attachments', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Chapters.references with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Reference}', + TypeNamePlural: '{i18n>References}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy References', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Chapters.footnotes with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Footnote}', + TypeNamePlural: '{i18n>Footnotes}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Footnotes', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Pages.attachments with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Attachment}', + TypeNamePlural: '{i18n>Attachments}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Attachments', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Pages.references with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Reference}', + TypeNamePlural: '{i18n>References}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy References', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Pages.footnotes with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Footnote}', + TypeNamePlural: '{i18n>Footnotes}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Footnotes', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +//////////////////////////////////////////////////////////////////////////// +// +// 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 + @title : '{i18n>Description}' + @UI.MultiLineText; +} + + +//////////////////////////////////////////////////////////////////////////// +// +// Reviews List +// +annotate my.Reviews with +@(UI : { + Identification : [ + { + Value : ID, + ![@UI.Hidden] + }, + {Value : title} + ], + SelectionFields : [ + book_ID, + rating + ], + LineItem : [ + { + Value : modifiedAt, + Label : 'Date' + }, + { + Value : createdBy, + Label : '{i18n>User}' + }, + { + $Type : 'UI.DataFieldForAnnotation', + Label : '{i18n>Book}', + Target : '@UI.FieldGroup#BookAndAuthor' + }, + { + $Type : 'UI.DataFieldForAnnotation', + Label : '{i18n>Rating}', + Target : '@UI.DataPoint#rating' + }, + { + Value : title, + Label : '{i18n>Review}' + } + ], + FieldGroup #BookAndAuthor : {Data : [ + {Value : book.title}, + {Value : book.author.name} + ]}, + DataPoint #rating : { + Value : rating, + Visualization : #Rating, + MinimumValue : 0, + MaximumValue : 5 + } +}); + +annotate my.Reviews with { + ID + @title : '{i18n>ID}' + @UI.HiddenFilter; + title + @title : '{i18n>Title}'; + book + @ValueList.entity : 'Books' + @title : '{i18n>Book}' + @Common : { + Text : book.title, + TextArrangement : #TextOnly + }; + rating + @title : '{i18n>Rating}'; + text + @title : '{i18n>Text}' + @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 : minorUnit} + ]}, +}); + +//////////////////////////////////////////////////////////////////////////// +// +// Fiori requires generated IDs to be annotated with @Core.Computed +// +using {cuid} from '@sap/cds/common'; + +annotate cuid with { + ID + @Core.Computed +} \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/fiori.html b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/fiori.html new file mode 100644 index 000000000..0a55fc123 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/fiori.html @@ -0,0 +1,30 @@ + + + + + + + + Bookshop + + + + + + + + + + diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/index.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/index.cds new file mode 100644 index 000000000..dcbf40e55 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/index.cds @@ -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 './reviews/fiori-service'; +using from './notes/fiori-service'; +using from './addresses/fiori-service'; +using from './common'; diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/fiori-service.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/fiori-service.cds new file mode 100644 index 000000000..102095b1a --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/fiori-service.cds @@ -0,0 +1,133 @@ +using NotesService from '../../srv/notes-mashup'; + +annotate NotesService.Notes with @odata.draft.enabled @(UI : { + LineItem : [ + { + Value : address.businessPartner, + Label : '{i18n>BusinessPartner}' + }, + { + Value : address.street, + Label : '{i18n>StreetName}' + }, + { + Value : address.city, + Label : '{i18n>CityName}' + }, + { + Value : note, + Label : '{i18n>Note}' + } + ], + HeaderInfo : { + TypeName : '{i18n>Note}', + TypeNamePlural : '{i18n>Notes}', + Title : {Value : '{i18n>Note}'}, + Description : {Value : ID}, + }, + PresentationVariant : { + Text : 'Default', + Visualizations : ['@UI.LineItem'] + }, + Facets : [ + { + $Type : 'UI.ReferenceFacet', + Target : '@UI.FieldGroup#Note', + Label : '{i18n>Note}', + }, + { + $Type : 'UI.ReferenceFacet', + Target : '@UI.FieldGroup#Address', + Label : '{i18n>ShippingAddress}', + } + ], + FieldGroup #Note : {Data : [ + { + Value : note, + Label : '{i18n>Note}' + } + ]}, + FieldGroup #Address : {Data : [ + { + Value : address_businessPartner, + Label : '{i18n>BusinessPartner}' + }, + { + Value : address.ID, + Label : '{i18n>ID}' + }, + { + Value : address.street, + Label : '{i18n>StreetName}' + }, + { + Value : address.houseNumber, + Label : '{i18n>HouseNumber}' + }, + { + Value : address.postalCode, + Label : '{i18n>PostalCode}' + }, + { + Value : address.city, + Label : '{i18n>CityName}' + }, + { + Value : address.country, + Label : '{i18n>Country}' + } + ]}, +}, Common : { + SideEffects #AddressChanges : { + SourceProperties : [address_businessPartner], + TargetEntities : [address] + } +}) { + ID + @title : '{i18n>ID}' + @UI.HiddenFilter; + note + @title : '{i18n>Note}' + @UI.MultiLineText; + address + @(Common : { + FieldControl : #Mandatory, + ValueList : { + CollectionPath : 'Addresses', + Label : '{i18n>ShippingAddress}', + SearchSupported : false, + Parameters : [ + { + $Type : 'Common.ValueListParameterOut', + LocalDataProperty : 'address_businessPartner', + ValueListProperty : 'businessPartner' + }, + { + $Type : 'Common.ValueListParameterOut', + LocalDataProperty : 'address_ID', + ValueListProperty : 'ID', + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'postalCode' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'city' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'country' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'street' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'houseNumber' + }, + ] + } + }); +}; diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/package.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/package.json new file mode 100644 index 000000000..555c053ee --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/package.json @@ -0,0 +1,12 @@ +{ + "name": "notes", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/webapp/Component.js b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/webapp/Component.js new file mode 100644 index 000000000..aa5843fc8 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/webapp/Component.js @@ -0,0 +1,3 @@ +sap.ui.define(["sap/fe/core/AppComponent"], ac => ac.extend("notes.Component", { + metadata:{ manifest:'json' } +})) diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/webapp/i18n/i18n.properties b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/webapp/i18n/i18n.properties new file mode 100644 index 000000000..e4d3ed2f6 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/webapp/i18n/i18n.properties @@ -0,0 +1,2 @@ +appTitle=Manage Notes +appDescription=Manage Notes - Sample Application diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/webapp/i18n/i18n_de.properties b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/webapp/i18n/i18n_de.properties new file mode 100644 index 000000000..5451c4e24 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/webapp/i18n/i18n_de.properties @@ -0,0 +1,2 @@ +appTitle=Administriere Notizen +appDescription=Administriere Notizen - Beispielanwendung diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/webapp/index.html b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/webapp/index.html new file mode 100644 index 000000000..d91b7503e --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/webapp/index.html @@ -0,0 +1,35 @@ + + + + + + + Manage Notes + + + + +
+ + diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/webapp/manifest.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/webapp/manifest.json new file mode 100644 index 000000000..f75a99b20 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/notes/webapp/manifest.json @@ -0,0 +1,120 @@ +{ + "_version": "1.8.0", + "sap.app": { + "id": "notes", + "type": "application", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + }, + "dataSources": { + "NotesService": { + "uri": "/api/notes/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + }, + "-sourceTemplate": { + "id": "ui5template.basicSAPUI5ApplicationProject", + "-id": "ui5template.smartTemplate", + "-version": "1.40.12" + }, + "crossNavigation": { + "inbounds": { + "Notes-manage": { + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "semanticObject": "Notes", + "action": "manage" + } + } + } + }, + "sap.ui5": { + "dependencies": { + "libs": { + "sap.fe.templates": {} + } + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "i18n/i18n.properties" + }, + "": { + "dataSource": "NotesService", + "settings": { + "synchronizationMode": "None", + "operationMode": "Server", + "autoExpandSelect" : true, + "earlyRequests": true, + "groupProperties": { + "default": { + "submit": "Auto" + } + } + } + } + }, + "routing": { + "routes": [ + { + "pattern": ":?query:", + "name": "NotesList", + "target": "NotesList" + }, + { + "pattern": "Notes({key}):?query:", + "name": "NotesDetails", + "target": "NotesDetails" + } + ], + "targets": { + "NotesList": { + "type": "Component", + "id": "NotesList", + "name": "sap.fe.templates.ListReport", + "options": { + "settings" : { + "entitySet" : "Notes", + "navigation" : { + "Notes" : { + "detail" : { + "route" : "NotesDetails" + } + } + } + } + } + }, + "NotesDetails": { + "type": "Component", + "id": "NotesDetails", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet" : "Notes" + } + } + } + } + }, + "contentDensities": { + "compact": true, + "cozy": true + } + }, + "sap.ui": { + "technology": "UI5", + "fullWidth": false + }, + "sap.fiori": { + "registrationIds": [], + "archeType": "transactional" + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/fiori-service.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/fiori-service.cds new file mode 100644 index 000000000..58a4bbde6 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/fiori-service.cds @@ -0,0 +1,293 @@ +/* + Annotations for the Manage Orders App +*/ + +using AdminService from '../../srv/admin-service'; + + +//////////////////////////////////////////////////////////////////////////// +// +// Common +// +annotate AdminService.OrderItems with { + book @( + Common : { + Text : book.title, + FieldControl : #Mandatory + }, + ValueList.entity : 'Books', + ); + quantity @(Common.FieldControl : #Mandatory); +} + +annotate AdminService.Orders with { + shippingAddress @(Common : { + FieldControl : #Mandatory, + ValueList : { + CollectionPath : 'Addresses', + Label : 'Addresses', + SearchSupported : 'true', + Parameters : [ + { + $Type : 'Common.ValueListParameterOut', + LocalDataProperty : 'shippingAddress_ID', + ValueListProperty : 'ID' + }, + { + $Type : 'Common.ValueListParameterOut', + LocalDataProperty : 'shippingAddress_businessPartner', + ValueListProperty : 'businessPartner' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'postalCode' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'city' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'country' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'street' + }, + { + $Type : 'Common.ValueListParameterDisplayOnly', + ValueListProperty : 'houseNumber' + }, + ] + } + }); +} + +//////////////////////////////////////////////////////////////////////////// +// +// UI +// +annotate AdminService.Orders with @( + title : '{i18n>Order}', + UI : { + //////////////////////////////////////////////////////////////////////////// + // + // Lists of Orders + // + SelectionFields : [ + createdAt, + createdBy + ], + LineItem : [ + { + Value : createdBy, + Label : '{i18n>Customer}' + }, + { + Value : total, + Label : '{i18n>Total}' + }, + { + Value : createdAt, + Label : '{i18n>Date}' + } + ], + //////////////////////////////////////////////////////////////////////////// + // + // Order Details + // + HeaderInfo : { + TypeName : '{i18n>Order}', + TypeNamePlural : '{i18n>Orders}', + Title : { + Label : '{i18n>OrderNumber}', //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 : '{i18n>Customer}' + }, + { + Value : createdAt, + Label : '{i18n>Date}' + }, + {Value : OrderNo}, + { + Value : 'shippingAddress', + Label : '{i18n>ID}' + } + ], + 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>ShippingAddress}', + Target : '@UI.FieldGroup#ShippingAddress' + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>Details}', + Target : '@UI.FieldGroup#Details' + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>OrderItems}', + Target : 'Items/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'ChangeHistoryFacet', + Label : '{i18n>ChangeHistory}', + Target : 'changes/@UI.PresentationVariant', + ![@UI.PartOfPreview]: false + } + ], + FieldGroup #Details : {Data : [ + { + Value : total, + Label : '{i18n>Total}' + }, + { + Value : currency_code, + Label : '{i18n>Currency}' + } + ]}, + FieldGroup #Created : {Data : [ + {Value : createdBy}, + {Value : createdAt}, + ]}, + FieldGroup #Modified : {Data : [ + {Value : modifiedBy}, + {Value : modifiedAt}, + ]}, + FieldGroup #ShippingAddress : {Data : [ + { + Value : shippingAddress_ID, + Label : '{i18n>ShippingAddress}' + }, + { + Value : shippingAddress.houseNumber, + Label : '{i18n>HouseNumber}' + }, + { + Value : shippingAddress.street, + Label : '{i18n>StreetName}' + }, + { + Value : shippingAddress.city, + Label : '{i18n>CityName}' + }, + { + Value : shippingAddress.postalCode, + Label : '{i18n>PostalCode}' + }, + ]} + }, + Common : { + SideEffects #ItemsChanges : { + SourceEntities : [Items], + TargetProperties : ['total'] + }, + SideEffects #CurrencyChanges : { + SourceProperties : [currency_code], + TargetEntities : [currency] + }, + SideEffects #AddressChanges : { + SourceProperties : [shippingAddress_ID], + TargetEntities : [shippingAddress] + } + } +) { + createdAt @UI.HiddenFilter : false; + createdBy @UI.HiddenFilter : false; + total + @Common.FieldControl : #ReadOnly + @Measures.ISOCurrency : currency.code; //Bind the currency field to the amount field +//In all services we always find currency as the code and not as an object that contains a property code +//it seems to work but at least to me this is unconventional modeling. +}; + +//The enity types name is AdminService.my_bookshop_OrderItems +//The annotations below are not generated in edmx WHY? +annotate AdminService.OrderItems with @( + title : '{i18n>OrderItem}', + UI : { + HeaderInfo : { + TypeName : '{i18n>OrderItem}', + TypeNamePlural : '{i18n>OrderItems}', + Title : {Value : book.title}, + Description : {Value : book.descr} + }, + // There is no filterbar for items so the selctionfileds is not needed + SelectionFields : [book_ID], + //////////////////////////////////////////////////////////////////////////// + // + // Lists of OrderItems + // + LineItem : [ + { + Value : book_ID, + Label : '{i18n>Books}' + }, + { + Value : quantity, + }, + { + Value : amount, + } + ], + Identification : [ //Is the main field group + //{Value: ID, Label:'{i18n>ID}'}, //A guid shouldn't be on the UI + { + Value : book_ID, + }, + { + Value : quantity, + }, + { + Value : amount, + } + ], + Facets : [{ + $Type : 'UI.ReferenceFacet', + Label : '{i18n>OrderItem}', + Target : '@UI.Identification' + }, ], + }, + Common : { + SideEffects #AmountChanges : { + SourceProperties : [quantity], + TargetProperties : ['amount'] + }, + SideEffects #BookChanges : { + SourceProperties : [book_ID], + TargetEntities : [book], + TargetProperties : ['amount'] + } + } +) { + @title: '{i18n>Amount}' + amount + @Common.FieldControl : #ReadOnly; + + @title: '{i18n>Quantity}' + quantity; + @title: '{i18n>Book}' + book; +//ERROR ALERT: The following line refering to the parents currency code will lead to a server error +//@Measures.ISOCurrency:parent.currency.code; //Bind the currency field to the quantity field of the parent +}; diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/package.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/package.json new file mode 100644 index 000000000..eecfe0e9f --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/package.json @@ -0,0 +1,12 @@ +{ + "name": "orders", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/webapp/Component.js b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/webapp/Component.js new file mode 100644 index 000000000..2417b6819 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/webapp/Component.js @@ -0,0 +1,3 @@ +sap.ui.define(["sap/fe/core/AppComponent"], ac => ac.extend("orders.Component", { + metadata:{ manifest:'json' } +})) diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/webapp/i18n/i18n.properties b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/webapp/i18n/i18n.properties new file mode 100644 index 000000000..441b619d8 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/webapp/i18n/i18n.properties @@ -0,0 +1,2 @@ +appTitle=Manage Orders +appDescription=Manage Orders - Sample Application diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/webapp/i18n/i18n_de.properties b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/webapp/i18n/i18n_de.properties new file mode 100644 index 000000000..df5222671 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/webapp/i18n/i18n_de.properties @@ -0,0 +1,2 @@ +appTitle=Administriere Bestellungen +appDescription=Administriere Bestellungen - Beispielanwendung diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/webapp/index.html b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/webapp/index.html new file mode 100644 index 000000000..1b3b73558 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/webapp/index.html @@ -0,0 +1,35 @@ + + + + + + + Manage Orders + + + + +
+ + \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/webapp/manifest.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/webapp/manifest.json new file mode 100644 index 000000000..758e31f2a --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/orders/webapp/manifest.json @@ -0,0 +1,184 @@ +{ + "_version": "1.8.0", + "sap.app": { + "id": "orders", + "type": "application", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + }, + "dataSources": { + "AdminService": { + "uri": "/api/admin/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + }, + "-sourceTemplate": { + "id": "ui5template.basicSAPUI5ApplicationProject", + "-id": "ui5template.smartTemplate", + "-version": "1.40.12" + }, + "crossNavigation": { + "inbounds": { + "Orders-manage": { + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "semanticObject": "Orders", + "action": "manage" + } + } + } + }, + "sap.ui5": { + "dependencies": { + "libs": { + "sap.fe.templates": {} + } + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "i18n/i18n.properties" + }, + "": { + "dataSource": "AdminService", + "settings": { + "synchronizationMode": "None", + "operationMode": "Server", + "autoExpandSelect" : true, + "earlyRequests": true, + "groupProperties": { + "default": { + "submit": "Auto" + } + } + } + } + }, + "routing": { + "routes": [ + { + "pattern": ":?query:", + "name": "OrdersList", + "target": "OrdersList" + }, + { + "pattern": "Orders({key}):?query:", + "name": "OrdersDetails", + "target": "OrdersDetails" + }, + { + "pattern": "Orders({boo})/Items({boo2}):?query:", + "name": "OrderItemsDetails", + "target": "OrderItemsDetails" + }, + { + "pattern": "Books({key}):?query:", + "name": "BooksDetails", + "target": "BooksDetails" + } + ], + "targets": { + "OrdersList": { + "type": "Component", + "id": "OrdersList", + "name": "sap.fe.templates.ListReport", + "options": { + "settings" : { + "entitySet" : "Orders", + "navigation" : { + "Orders" : { + "detail" : { + "route" : "OrdersDetails" + } + } + } + } + } + }, + "OrdersDetails": { + "type": "Component", + "id": "OrdersDetails", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet": "Orders", + "navigation" : { + "Items": { + "detail": { + "route": "OrderItemsDetails" + } + }, + "book": { + "detail": { + "route": "BooksDetails" + } + }, + "dummy": { + "detail": { + "route": "BooksDetails" + } + } + } + } + } + }, + "OrderItemsDetails": { + "type": "Component", + "id": "OrderItemsDetails", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet": "OrderItems" + } + } + }, + "BooksDetails": { + "type": "Component", + "id": "BooksDetails", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet": "Books", + "navigation": { + "author": { + "detail": { + "route": "AuthorsDetails" + } + } + } + } + } + }, + "AuthorsDetails": { + "type": "Component", + "id": "AuthorsDetails", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet": "Authors" + } + } + } + } + }, + "contentDensities": { + "compact": true, + "cozy": true + } + }, + "sap.ui": { + "technology": "UI5", + "fullWidth": false + }, + "sap.fiori": { + "registrationIds": [], + "archeType": "transactional" + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/package-lock.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/package-lock.json new file mode 100644 index 000000000..cc337716f --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/package-lock.json @@ -0,0 +1,2014 @@ +{ + "name": "approuter", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "approuter", + "dependencies": { + "@sap/approuter": "^13" + } + }, + "node_modules/@sap/approuter": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@sap/approuter/-/approuter-13.1.1.tgz", + "integrity": "sha512-IinOHss1M59eEW4b8lCjSKsi4upaesh82tiH/TOFmSgbREawKct7IF743oN953S0JY8y5w5dcfTGToU8lfjTYA==", + "dependencies": { + "@sap/audit-logging": "5.6.3", + "@sap/e2e-trace": "^3.0.0", + "@sap/logging": "^6.1.1", + "@sap/xsenv": "^3.4.0", + "@sap/xssec": "^3.2.17", + "agentkeepalive": "2.0.5", + "axios": "0.27.2", + "axios-cookiejar-support": "2.0.3", + "base64-url": "2.3.3", + "basic-auth": "1.0.3", + "body-parser": "1.20.0", + "cf-nodejs-logging-support": "^6.14.0", + "commander": "2.9.0", + "compressible": "2.0.18", + "compression": "1.7.4", + "connect": "3.6.5", + "cookie": "0.2.2", + "cookie-parser": "1.3.5", + "cookie-signature": "1.1.0", + "debug": "4.3.2", + "deepmerge": "2.1.1", + "encodeurl": "1.0.2", + "express-session": "1.17.0", + "http-proxy-agent": "4.0.1", + "https-proxy-agent": "5.0.0", + "ioredis": "4.28.5", + "jwt-decode": "2.0.1", + "lodash": "4.17.21", + "lru-cache": "4.0.0", + "mime": "1.4.1", + "ms": "2.1.1", + "mustache": "2.2.1", + "node-cache": "4.1.1", + "node-forge": "^1.3.0", + "passport": "^0.6.0", + "query-string": "7.1.2", + "request-stats": "2.0.1", + "safe-regex": "1.1.0", + "scmp": "1.0.0", + "send": "0.16.2", + "serve-static": "1.13.2", + "tough-cookie": "4.0.0", + "tv4": "1.2.7", + "uid-safe": "2.1.5", + "urijs": "^1.19.11", + "uuid": "8.3.2", + "validator": "13.7.0", + "verror": "1.10.0", + "ws": "7.4.6" + }, + "engines": { + "node": "^14.0.0 || ^16.0.0" + } + }, + "node_modules/@sap/audit-logging": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/@sap/audit-logging/-/audit-logging-5.6.3.tgz", + "integrity": "sha512-Uden+nsIxfbnsVrW9Jm3spZ8sNgCOdmZMbBQ24CeElW7qv82rH3Rpm2b+9qRgahWGxQlwws5LPZc0zESMw/mdA==", + "hasShrinkwrap": true, + "dependencies": { + "@sap/xssec": "^3.2.15", + "debug": "4.3.3", + "fetch-retry": "4.1.0", + "node-cache": "5.1.0", + "node-fetch": "2.6.7" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || ^14.0.0 || ^16.0.0 || ^18.0.0" + } + }, + "node_modules/@sap/audit-logging/node_modules/@sap/xssec": { + "version": "3.2.15", + "dependencies": { + "axios": "^0.26.0", + "debug": "^4.3.2", + "jsonwebtoken": "^9.0.0", + "lru-cache": "^6.0.0", + "node-rsa": "^1.1.1", + "valid-url": "1.0.9" + } + }, + "node_modules/@sap/audit-logging/node_modules/asn1": { + "version": "0.2.6", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/@sap/audit-logging/node_modules/axios": { + "version": "0.26.1", + "dependencies": { + "follow-redirects": "^1.14.8" + } + }, + "node_modules/@sap/audit-logging/node_modules/buffer-equal-constant-time": { + "version": "1.0.1" + }, + "node_modules/@sap/audit-logging/node_modules/clone": { + "version": "2.1.2" + }, + "node_modules/@sap/audit-logging/node_modules/debug": { + "version": "4.3.3", + "dependencies": { + "ms": "2.1.2" + } + }, + "node_modules/@sap/audit-logging/node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@sap/audit-logging/node_modules/fetch-retry": { + "version": "4.1.0" + }, + "node_modules/@sap/audit-logging/node_modules/follow-redirects": { + "version": "1.15.2" + }, + "node_modules/@sap/audit-logging/node_modules/jsonwebtoken": { + "version": "9.0.0", + "dependencies": { + "jws": "^3.2.2", + "lodash": "^4.17.21", + "ms": "^2.1.1", + "semver": "^7.3.8" + } + }, + "node_modules/@sap/audit-logging/node_modules/jwa": { + "version": "1.4.1", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@sap/audit-logging/node_modules/jws": { + "version": "3.2.2", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@sap/audit-logging/node_modules/lodash": { + "version": "4.17.21" + }, + "node_modules/@sap/audit-logging/node_modules/lru-cache": { + "version": "6.0.0", + "dependencies": { + "yallist": "^4.0.0" + } + }, + "node_modules/@sap/audit-logging/node_modules/ms": { + "version": "2.1.2" + }, + "node_modules/@sap/audit-logging/node_modules/node-cache": { + "version": "5.1.0", + "dependencies": { + "clone": "2.x" + } + }, + "node_modules/@sap/audit-logging/node_modules/node-fetch": { + "version": "2.6.7", + "dependencies": { + "whatwg-url": "^5.0.0" + } + }, + "node_modules/@sap/audit-logging/node_modules/node-rsa": { + "version": "1.1.1", + "dependencies": { + "asn1": "^0.2.4" + } + }, + "node_modules/@sap/audit-logging/node_modules/safe-buffer": { + "version": "5.2.1" + }, + "node_modules/@sap/audit-logging/node_modules/safer-buffer": { + "version": "2.1.2" + }, + "node_modules/@sap/audit-logging/node_modules/semver": { + "version": "7.3.8", + "dependencies": { + "lru-cache": "^6.0.0" + } + }, + "node_modules/@sap/audit-logging/node_modules/tr46": { + "version": "0.0.3" + }, + "node_modules/@sap/audit-logging/node_modules/valid-url": { + "version": "1.0.9" + }, + "node_modules/@sap/audit-logging/node_modules/webidl-conversions": { + "version": "3.0.1" + }, + "node_modules/@sap/audit-logging/node_modules/whatwg-url": { + "version": "5.0.0", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/@sap/audit-logging/node_modules/yallist": { + "version": "4.0.0" + }, + "node_modules/@sap/e2e-trace": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@sap/e2e-trace/-/e2e-trace-3.2.0.tgz", + "integrity": "sha512-tNqLk/RhX6oc2ScFCJkVtSGPWqrxRLAUfIsCN1Dn4yGHc+gHQVdmyVTDkgKdgw9m4kU+emD2PjDXpo2VwAb0Pg==", + "hasShrinkwrap": true, + "dependencies": { + "request-stats": "3.0.0" + }, + "engines": { + "node": "^8.0.0 || ^10.0.0 || ^12.0.0 || ^14.0.0 || ^16.0.0 || ^18.0.0" + } + }, + "node_modules/@sap/e2e-trace/node_modules/http-headers": { + "version": "3.0.2", + "dependencies": { + "next-line": "^1.1.0" + } + }, + "node_modules/@sap/e2e-trace/node_modules/next-line": { + "version": "1.1.0" + }, + "node_modules/@sap/e2e-trace/node_modules/once": { + "version": "1.4.0", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/@sap/e2e-trace/node_modules/request-stats": { + "version": "3.0.0", + "dependencies": { + "http-headers": "^3.0.1", + "once": "^1.4.0" + } + }, + "node_modules/@sap/e2e-trace/node_modules/wrappy": { + "version": "1.0.2" + }, + "node_modules/@sap/logging": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@sap/logging/-/logging-6.2.0.tgz", + "integrity": "sha512-2AYADnDN/1u8Fpa9EqTABnLl4GPAwMoOXaWMFJKwrvSTSr6RSQK924uUMQQBClwcwCwktcf4xlrWCFSztBjfxQ==", + "hasShrinkwrap": true, + "dependencies": { + "@sap/e2e-trace": "^3.1.0", + "lodash": "4.17.21", + "moment": "2.29.4" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || ^14.0.0 || ^16.0.0 || ^18.0.0" + } + }, + "node_modules/@sap/logging/node_modules/@sap/e2e-trace": { + "version": "3.2.0", + "dependencies": { + "request-stats": "3.0.0" + } + }, + "node_modules/@sap/logging/node_modules/@sap/e2e-trace/node_modules/http-headers": { + "version": "3.0.2", + "dependencies": { + "next-line": "^1.1.0" + } + }, + "node_modules/@sap/logging/node_modules/@sap/e2e-trace/node_modules/next-line": { + "version": "1.1.0" + }, + "node_modules/@sap/logging/node_modules/@sap/e2e-trace/node_modules/once": { + "version": "1.4.0", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/@sap/logging/node_modules/@sap/e2e-trace/node_modules/request-stats": { + "version": "3.0.0", + "dependencies": { + "http-headers": "^3.0.1", + "once": "^1.4.0" + } + }, + "node_modules/@sap/logging/node_modules/@sap/e2e-trace/node_modules/wrappy": { + "version": "1.0.2" + }, + "node_modules/@sap/logging/node_modules/lodash": { + "version": "4.17.21" + }, + "node_modules/@sap/logging/node_modules/moment": { + "version": "2.29.4" + }, + "node_modules/@sap/xsenv": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@sap/xsenv/-/xsenv-3.4.0.tgz", + "integrity": "sha512-bZ/NFhS+wZI0JlMO1OOBEThfyOTmf2x5oQ+wToJGkZ2T5+gLUE3emZiC4iHA+BuSmUtO+vYoe29Q1qiE4qaiJQ==", + "hasShrinkwrap": true, + "dependencies": { + "debug": "4.3.3", + "node-cache": "^5.1.0", + "verror": "1.10.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || ^14.0.0 || ^16.0.0 || ^18.0.0" + } + }, + "node_modules/@sap/xsenv/node_modules/assert-plus": { + "version": "1.0.0" + }, + "node_modules/@sap/xsenv/node_modules/clone": { + "version": "2.1.2" + }, + "node_modules/@sap/xsenv/node_modules/core-util-is": { + "version": "1.0.2" + }, + "node_modules/@sap/xsenv/node_modules/debug": { + "version": "4.3.3", + "dependencies": { + "ms": "2.1.2" + } + }, + "node_modules/@sap/xsenv/node_modules/extsprintf": { + "version": "1.4.1" + }, + "node_modules/@sap/xsenv/node_modules/ms": { + "version": "2.1.2" + }, + "node_modules/@sap/xsenv/node_modules/node-cache": { + "version": "5.1.2", + "dependencies": { + "clone": "2.x" + } + }, + "node_modules/@sap/xsenv/node_modules/verror": { + "version": "1.10.0", + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/@sap/xssec": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@sap/xssec/-/xssec-3.6.1.tgz", + "integrity": "sha512-OJouwIWClefpsJ8rVCziEydeDHDNOMA4hjsjw9OqolbbObaiYMMDRU0YJbPe7XL5JkLgrtt+CLCBCsNERxcCZg==", + "dependencies": { + "axios": "^1.6", + "debug": "^4.3.4", + "jsonwebtoken": "^9.0.2", + "node-rsa": "^1.1.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@sap/xssec/node_modules/axios": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/@sap/xssec/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@sap/xssec/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-2.0.5.tgz", + "integrity": "sha512-dlXxjfkCrcEPmvJju6ypP6/eq1q0l+cu0u10IhKfiwMoy4yH73n0TQ2jMO2H39xbcC3Q4cWUFPkNk1b3GLEklg==", + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "dependencies": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "node_modules/axios-cookiejar-support": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/axios-cookiejar-support/-/axios-cookiejar-support-2.0.3.tgz", + "integrity": "sha512-tvMB+0JhxXLjjvePsXzqXhBI4DMlW4ImR4pKKNl+xclwF0IviNV+CkuhubQCCFjPzOXv7PIzOq3z7WFiF9pMpw==", + "dependencies": { + "http-cookie-agent": "^1.0.2" + }, + "engines": { + "node": ">=12.19.0 <13.0.0 || >=14.5.0" + }, + "peerDependencies": { + "axios": ">=0.20.0", + "tough-cookie": ">=4.0.0" + } + }, + "node_modules/base64-url": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/base64-url/-/base64-url-2.3.3.tgz", + "integrity": "sha512-dLMhIsK7OplcDauDH/tZLvK7JmUZK3A7KiQpjNzsBrM6Etw7hzNI1tLEywqJk9NnwkgWuFKSlx/IUO7vF6Mo8Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/basic-auth": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.0.3.tgz", + "integrity": "sha512-fkXSqXkCTgBy5HVNQ2wP1Fnc/JZjnREwM3hfU8h5RyUN8X9WMQBJem6ZmlsSs7Y4f3fQ7z09vcARgOa0iaPaZA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/body-parser": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/cf-nodejs-logging-support": { + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/cf-nodejs-logging-support/-/cf-nodejs-logging-support-6.14.1.tgz", + "integrity": "sha512-ORQL/J0qe2isOPwlXKafaCGmNkQLngb/6KgxLJQ+pfxynAfVUn6tJMtEwH7U0izBSzEtFsYGXa6H4DmIH/8Hrg==", + "dependencies": { + "json-stringify-safe": "^5.0.1", + "jsonwebtoken": "^9.0.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha512-bmkUukX8wAOjHdN26xj5c4ctEV22TQ7dQYhSmuckKhToXrkUn0iIaolHdIxYYqD55nhpSPA9zPQ1yP57GdXP2A==", + "dependencies": { + "graceful-readlink": ">= 1.0.0" + }, + "engines": { + "node": ">= 0.6.x" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/connect": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.5.tgz", + "integrity": "sha512-B+WTJ0bDgjQugnbNF7fWGvwEgTj9Isdk3Y7yTZlgCuVe+hpl/do8frEMeimx7sRMPW3oZA+EsC9uDZL8MaaAwQ==", + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.0.6", + "parseurl": "~1.3.2", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.2.2.tgz", + "integrity": "sha512-QT1/SH6oF6jrC9K4rlWpa/5FgqUZuh/Ohl4NvGAgSm67DsieBdTz/XsiVQwBKEJMnw7Tui5uBuC7k1yUAmPO2g==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-parser": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.3.5.tgz", + "integrity": "sha512-YN/8nzPcK5o6Op4MIzAd4H4qUal5+3UaMhVIeaafFYL0pKvBQA/9Yhzo7ZwvBpjdGshsiTAb1+FC37M6RdPDFg==", + "dependencies": { + "cookie": "0.1.3", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-parser/node_modules/cookie": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz", + "integrity": "sha512-mWkFhcL+HVG1KjeCjEBVJJ7s4sAGMLiBDFSDs4bzzvgLZt7rW8BhP6XV/8b1+pNvx/skd3yYxPuaF3Z6LlQzyw==", + "engines": { + "node": "*" + } + }, + "node_modules/cookie-parser/node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/cookie-signature": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.1.0.tgz", + "integrity": "sha512-Alvs19Vgq07eunykd3Xy2jF0/qSNv2u7KDbAek9H5liV1UMijbqFs5cycZvv5dVsvseT/U4H8/7/w8Koh35C4A==", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + }, + "node_modules/debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/deepmerge": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.1.1.tgz", + "integrity": "sha512-urQxA1smbLZ2cBbXbaYObM1dJ82aJ2H57A1C/Kklfh/ZN1bgH4G/n5KWhdNfOK11W98gqZfyYj7W4frJJRwA2w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/denque": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express-session": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.0.tgz", + "integrity": "sha512-t4oX2z7uoSqATbMfsxWMbNjAL0T5zpvcJCk3Z9wnPPN7ibddhnmDZXHfEcoBMG2ojKXZoCyPMc5FbtK+G7SoDg==", + "dependencies": { + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.3", + "safe-buffer": "5.2.0", + "uid-safe": "~2.1.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/express-session/node_modules/cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express-session/node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/express-session/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express-session/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/express-session/node_modules/safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + }, + "node_modules/extsprintf": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", + "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/filter-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", + "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.6.tgz", + "integrity": "sha512-immlyyYCPWG2tajlYBhZ6cjLAv1QAclU8tKS0d27ZtPqm/+iddy16GT3xLExg+V4lIETLpPwaYQAlZHNE//dPA==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.3.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w==" + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-cookie-agent": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/http-cookie-agent/-/http-cookie-agent-1.0.6.tgz", + "integrity": "sha512-Ei0BDjMfy6MSXATmCZ5nWr935NLYl6eD/BTxVGOIrKAlg4xDtMdk+8a+caq6Qwa4FACn+vACj89pFKlXmHOnkQ==", + "dependencies": { + "agent-base": "^6.0.2" + }, + "engines": { + "node": ">=12.19.0 <13.0.0 || >=14.5.0" + }, + "peerDependencies": { + "tough-cookie": "^4.0.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-headers": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-headers/-/http-headers-3.0.2.tgz", + "integrity": "sha512-87E1I+2Wg4dxxz4rcxElo3dxO/w1ZtgL1yA0Sb6vH3qU16vRKq1NjWQv9SCY3ly2OQROcoxHZOUpmelS+k6wOw==", + "dependencies": { + "next-line": "^1.1.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ioredis": { + "version": "4.28.5", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.28.5.tgz", + "integrity": "sha512-3GYo0GJtLqgNXj4YhrisLaNNvWSNwSS2wS4OELGfGxH8I69+XfNdnmV1AyN+ZqMh0i7eX+SWjrwFKDBDgfBC1A==", + "dependencies": { + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.1", + "denque": "^1.1.0", + "lodash.defaults": "^4.2.0", + "lodash.flatten": "^4.4.0", + "lodash.isarguments": "^3.1.0", + "p-map": "^2.1.0", + "redis-commands": "1.7.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jwt-decode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.0.1.tgz", + "integrity": "sha512-/KEXk2wGfWoSM2SHQk8mq9n/Rd6ahB0XIZt0jEcNy4tQXeDHU4oNOGK1shSVstIQm97qowy6dFgUAHB3zbOD8g==" + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, + "node_modules/lru-cache": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.0.tgz", + "integrity": "sha512-WKhDkjlLwzE8jAQdQlsxLUQTPXLCKX/4cJk6s5AlRtJkDBk0IKH5O51bVDH61K9N4bhbbyvLM6EiOuE8ovApPA==", + "dependencies": { + "pseudomap": "^1.0.1", + "yallist": "^2.0.0" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "bin": { + "mime": "cli.js" + } + }, + "node_modules/mime-db": { + "version": "1.53.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.53.0.tgz", + "integrity": "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "node_modules/mustache": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-2.2.1.tgz", + "integrity": "sha512-azYRexmi9y6h2lk2JqfBLh1htlDMjKYyEYOkxoGKa0FRdr5aY4f5q8bH4JIecM181DtUEYLSz8PcRO46mgzMNQ==", + "bin": { + "mustache": "bin/mustache" + }, + "engines": { + "npm": ">=1.4.0" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/next-line": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-line/-/next-line-1.1.0.tgz", + "integrity": "sha512-+I10J3wKNoKddNxn0CNpoZ3eTZuqxjNM3b1GImVx22+ePI+Y15P8g/j3WsbP0fhzzrFzrtjOAoq5NCCucswXOQ==" + }, + "node_modules/node-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-4.1.1.tgz", + "integrity": "sha512-1IdglJ3+6RO7j2jGVSbWG7CD/H7axG770BbuopZNDqKpQu1ol89xC4Qc+hd6uBEewjsoCZ6xRIY8BRa5PkHgTQ==", + "dependencies": { + "clone": "2.x", + "lodash": "4.x" + }, + "engines": { + "node": ">= 0.4.6" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-rsa": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/node-rsa/-/node-rsa-1.1.1.tgz", + "integrity": "sha512-Jd4cvbJMryN21r5HgxQOpMEqv+ooke/korixNNK3mGqfGJmy0M77WDDzo/05969+OkMy3XW1UuZsSmW9KQm7Fw==", + "dependencies": { + "asn1": "^0.2.4" + } + }, + "node_modules/object-inspect": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/passport": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.6.0.tgz", + "integrity": "sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" + }, + "node_modules/psl": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.13.0.tgz", + "integrity": "sha512-BFwmFXiJoFqlUpZ5Qssolv15DMyc84gTBds1BjsV1BfXEo1UyyD7GsmN67n7J77uRhoSNW1AXtXKPLcBFQn9Aw==", + "dependencies": { + "punycode": "^2.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/query-string": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.2.tgz", + "integrity": "sha512-KPbFzz/8pmtYOMH6zlYZgqTYJKQ18FxwfW3RLHIBwHWQ0iQG18X16XtIOk68ddfaM6j3grjYSnMPMrqQEjwR4w==", + "dependencies": { + "decode-uri-component": "^0.2.1", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/redis-commands": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz", + "integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==" + }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/request-stats": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/request-stats/-/request-stats-2.0.1.tgz", + "integrity": "sha512-GZQvTZqbUx9gXrRfj1c9pMcFzyLeJEpV2P5qXxGwf1I2ZRswRsCNYPsuwnFLNRZQamlsrinzKQnExXBGgFzFCw==", + "dependencies": { + "http-headers": "^3.0.1", + "once": "^1.4.0" + } + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "engines": { + "node": ">=0.12" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/scmp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/scmp/-/scmp-1.0.0.tgz", + "integrity": "sha512-gCzsBFLpXrXnq60hYFV4hc4b5a3nIWTKtFWMYvlcXqs5gHKTR445CO3QbFRZW/O+9tRIVTeC46/MXbq1Se/1Sw==", + "deprecated": "scmp v2 uses improved core crypto comparison since Node v6.6.0" + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/send/node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==" + }, + "node_modules/send/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/send/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/send/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "node_modules/send/node_modules/statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/split-on-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" + }, + "node_modules/statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha512-wuTCPGlJONk/a1kqZ4fQM2+908lC7fa7nPYpTC1EhnvqLX/IICbeP1OZGDtA374trpSq68YubKUMo8oRhN46yg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tv4": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/tv4/-/tv4-1.2.7.tgz", + "integrity": "sha512-7W00xKKK9ccSXbN8E1FUKe+PJKlQc3HcPRM1y9WnplFVucoWFBpTNCGJNMHG04+yf5lQKUKx71yt0mluqnbCzw==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "dependencies": { + "random-bytes": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/urijs": { + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validator": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" + } + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/package.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/package.json new file mode 100644 index 000000000..fa9d34967 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/package.json @@ -0,0 +1,9 @@ +{ + "name": "approuter", + "dependencies": { + "@sap/approuter": "16.8.2" + }, + "scripts": { + "start": "node node_modules/@sap/approuter/approuter.js" + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/fiori-service.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/fiori-service.cds new file mode 100644 index 000000000..ee77c5c4d --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/fiori-service.cds @@ -0,0 +1,90 @@ +/* + Annotations for the Browse Books App +*/ + +using ReviewService from '../../srv/review-service'; + +annotate ReviewService.Reviews with @(UI : { + HeaderInfo : { + TypeName : '{i18n>Review}', + TypeNamePlural : '{i18n>Reviews}', + Title : {Value : title}, + Description : {Value : createdBy}, + }, + PresentationVariant : { + Text : 'Default', + SortOrder : [{ + Property : modifiedAt, + Descending : true + }], + Visualizations : ['@UI.LineItem'] + }, + SelectionFields : [ + book_ID, + rating + ], + HeaderFacets : [{ + $Type : 'UI.ReferenceFacet', + Target : '@UI.DataPoint#rating' + }, ], + Facets : [ + { + $Type : 'UI.ReferenceFacet', + Target : '@UI.FieldGroup#General', + Label : '{i18n>General}' + }, + { + $Type : 'UI.ReferenceFacet', + Target : '@UI.FieldGroup#Review', + Label : '{i18n>Review}', + } + ], + FieldGroup #General : {Data : [ + { + Value : createdAt, + Label : '{i18n>Created}' + }, + { + Value : createdBy, + Label : '{i18n>CreatedBy}' + }, + { + Value : modifiedAt, + Label : '{i18n>Modified}' + }, + { + Value : modifiedBy, + Label : '{i18n>ModifiedBy}' + }, + {Value : book_ID}, + ]}, + FieldGroup #Review : {Data : [ + { + Value : rating, + Label : '{i18n>Rating}' + }, + { + Value : title, + Label : '{i18n>Title}' + }, + { + Value : text, + Label : '{i18n>Text}' + } + ]}, + FieldGroup #BookAndAuthor : {Data : [ + {Value : book.title}, + {Value : book.author.name} + ]}, + DataPoint #rating : { + Title : '{i18n>Rating}', + Value : rating, + Visualization : #Rating, + MinimumValue : 0, + MaximumValue : 5 + } +}) { + rating @title : '{i18n>Rating}'; + title @title : '{i18n>Title}'; + text @title : '{i18n>Text}' @UI.MultiLineText; +}; diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/package.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/package.json new file mode 100644 index 000000000..22ad679de --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/package.json @@ -0,0 +1,12 @@ +{ + "name": "reviews", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/webapp/Component.js b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/webapp/Component.js new file mode 100644 index 000000000..4140a28ee --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/webapp/Component.js @@ -0,0 +1,3 @@ +sap.ui.define(["sap/fe/core/AppComponent"], ac => ac.extend("reviews.Component", { + metadata:{ manifest:'json' } +})) diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/webapp/i18n/i18n.properties b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/webapp/i18n/i18n.properties new file mode 100644 index 000000000..9aadf3e7c --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/webapp/i18n/i18n.properties @@ -0,0 +1,2 @@ +appTitle=Manage Reviews +appDescription=Manage Reviews - Sample Application diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/webapp/i18n/i18n_de.properties b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/webapp/i18n/i18n_de.properties new file mode 100644 index 000000000..1cc53e4cc --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/webapp/i18n/i18n_de.properties @@ -0,0 +1,2 @@ +appTitle=Administriere Reviews +appDescription=Administriere Reviews - Beispielanwendung diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/webapp/index.html b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/webapp/index.html new file mode 100644 index 000000000..d22158946 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/webapp/index.html @@ -0,0 +1,35 @@ + + + + + + + Manage Reviews + + + + +
+ + \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/webapp/manifest.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/webapp/manifest.json new file mode 100644 index 000000000..78dd8f8c6 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/reviews/webapp/manifest.json @@ -0,0 +1,142 @@ +{ + "_version": "1.8.0", + "sap.app": { + "id": "reviews", + "type": "application", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + }, + "dataSources": { + "ReviewService": { + "uri": "/api/review/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + }, + "-sourceTemplate": { + "id": "ui5template.basicSAPUI5ApplicationProject", + "-id": "ui5template.smartTemplate", + "-version": "1.40.12" + }, + "crossNavigation": { + "inbounds": { + "Reviews-manage": { + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "semanticObject": "Reviews", + "action": "manage" + } + } + } + }, + "sap.ui5": { + "dependencies": { + "libs": { + "sap.fe.templates": {} + } + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "i18n/i18n.properties" + }, + "": { + "dataSource": "ReviewService", + "settings": { + "synchronizationMode": "None", + "operationMode": "Server", + "autoExpandSelect" : true, + "earlyRequests": true, + "groupProperties": { + "default": { + "submit": "Auto" + } + } + } + } + }, + "routing": { + "routes": [ + { + "pattern": ":?query:", + "name": "ReviewsList", + "target": "ReviewsList" + }, + { + "pattern": "Reviews({key}):?query:", + "name": "ReviewsDetails", + "target": "ReviewsDetails" + }, + { + "pattern": "Reviews({key}/book({key2}):?query:", + "name": "BooksDetails", + "target": "BooksDetails" + } + ], + "targets": { + "ReviewsList": { + "type": "Component", + "id": "ReviewsList", + "name": "sap.fe.templates.ListReport", + "options": { + "settings" : { + "entitySet" : "Reviews", + "navigation" : { + "Reviews" : { + "detail" : { + "route" : "ReviewsDetails" + } + } + } + } + } + }, + "ReviewsDetails": { + "type": "Component", + "id": "ReviewsDetails", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet" : "Reviews", + "navigation" : { + "Books" : { + "detail" : { + "route" : "BooksDetails" + } + } + } + } + } + }, + "BooksDetails": { + "type": "Component", + "id": "BooksDetails", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings" : { + "entitySet" : "Books" + } + } + } + } + }, + "contentDensities": { + "compact": true, + "cozy": true + } + }, + "sap.ui": { + "technology": "UI5", + "fullWidth": false + }, + "sap.fiori": { + "registrationIds": [], + "archeType": "transactional" + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/vue/app.js b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/vue/app.js new file mode 100644 index 000000000..8b4a6f052 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/vue/app.js @@ -0,0 +1,122 @@ +/* global Vue axios */ //> from index.html +const $ = (sel) => document.querySelector(sel); + +const httpClient = axios.create({ + withCredentials: true, +}); + +// adding csrf token to request headers +axios + .head("/api/browse", { + headers: { + "X-CSRF-Token": "Fetch", + "X-Requested-With": "XMLHttpRequest", + }, + }) + .then((res) => { + xcsrfToken = res.headers["x-csrf-token"]; + httpClient.defaults.headers.common["X-CSRF-Token"] = xcsrfToken; + }); + +const GET = (url) => httpClient.get("/api/browse" + url); +const POST = (cmd, data) => httpClient.post("/api/browse" + cmd, data); + +const bookshop = new Vue({ + el: "#app", + + data: { + books: [], + reviews: [], + book: undefined, + review: undefined, + order: { quantity: 1, succeeded: "", failed: "" }, + message: {}, + Ratings: Object.entries({ + 5: "★★★★★", + 4: "★★★★", + 3: "★★★", + 2: "★★", + 1: "★", + }).reverse(), + }, + + methods: { + searchBooks: ({ target: { value: v } }) => + bookshop.fetchBooks(v && "&$search=" + v), + + searchReviews: ({ target: { value: v } }) => + bookshop.fetchReviews(v && "?$search=" + v), + + async fetchBooks(etc = "") { + const { data } = await GET(`/Books?$expand=author,genre,currency${etc}`); + bookshop.books = data.value; + }, + + async fetchReviews(etc = "") { + const { data } = await GET( + `/Books(ID=${bookshop.book.ID})/reviews${etc}` + ); + bookshop.reviews = data.value; + }, + + async inspectBook(eve) { + const book = (bookshop.book = + bookshop.books[eve.currentTarget.rowIndex - 1]); + const res = await GET( + `/Books(ID=${book.ID})?$expand=reviews&$select=descr,stock` + ); + Object.assign(book, res.data); + bookshop.order = { quantity: 1 }; + bookshop.reviews = book.reviews; + setTimeout(() => $("form > input").focus(), 111); + }, + + async submitOrder() { + const { book, order } = bookshop, + quantity = parseInt(bookshop.order.quantity) || 1; // REVISIT: Okra should be less strict + try { + const res = await POST(`/submitOrder`, { quantity, book: book.ID }); + book.stock = res.data.stock; + bookshop.order = { + quantity, + succeeded: `Successfully ordered ${quantity} item(s).`, + }; + } catch (e) { + bookshop.order = { quantity, failed: e.response.data.error.message }; + } + }, + + async inspectReview(eve) { + bookshop.review = bookshop.reviews[eve.currentTarget.rowIndex - 1]; + }, + + newReview() { + bookshop.review = {}; + bookshop.message = {}; + }, + + async submitReview() { + const review = bookshop.review; + review.rating = parseInt(review.rating); // REVISIT: Okra should be less strict + const payload = { + rating: review.rating, + title: review.title, + text: review.text, + }; + try { + await POST( + `/Books(ID=${bookshop.book.ID})/CatalogService.addReview`, + payload + ); + bookshop.message = { + succeeded: "Your review was submitted successfully. Thanks.", + }; + } catch (e) { + bookshop.message = { failed: e.response.data.error.message }; + } + }, + }, +}); + +// initially fill list of books +bookshop.fetchBooks(); diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/vue/index.html b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/vue/index.html new file mode 100644 index 000000000..f103c836b --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/vue/index.html @@ -0,0 +1,104 @@ + + + + + Capire Bookshop + + + + + + + +
+ +

{{ document.title }}

+ + + + + + + + + + + + + + + + + + +
Book Author Genre Rating Price
{{ book.title }}{{ book.author.name }}{{ book.genre.name }} + {{ ('★'.repeat(Math.round(book.rating))+'☆☆☆☆☆').slice(0,5) }} + {{ book.currency && book.currency.symbol }} {{ book.price }}
+ +
+ +
+ + +
+

{{ book.title }}

+

{{ book.descr }}

+ +

Reviews

+ + + + + + + + + + + + + + + + +
Date User Rating Title
{{ review.modifiedAt | datetime }}{{ review.createdBy }} + {{ ('★'.repeat(Math.round(review.rating))+'☆☆☆☆☆').slice(0,5) }} + {{ review.title }}
+ + + +
+ + + + + {{ message.succeeded }} + {{ message.failed }} +
+
+ ( click on a row to see details... ) +
+ +
+
+ ( click on a row to see details... ) +
+ +
+ + + + + diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/app/xs-app.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/xs-app.json new file mode 100644 index 000000000..f6adf5a45 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/app/xs-app.json @@ -0,0 +1,78 @@ +{ + "welcomeFile": "/app/fiori.html", + "authenticationMethod": "route", + "routes": [ + { + "source": "^/app/(.*)$", + "cacheControl": "no-cache, no-store, must-revalidate", + "target": "$1", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/appconfig/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/browse/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/admin/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/orders/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/reviews/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/notes/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/addresses/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/vue/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/api/admin/(.*)", + "authenticationType": "xsuaa", + "destination": "backend" + }, + { + "source": "^/api/browse/(.*)", + "authenticationType": "xsuaa", + "destination": "backend" + }, + { + "source": "^/api/review/(.*)", + "authenticationType": "xsuaa", + "destination": "backend" + }, + { + "source": "^/api/notes/(.*)", + "authenticationType": "xsuaa", + "destination": "backend" + }, + { + "source": "^/api/(.*)$", + "authenticationType": "none", + "destination": "backend" + } + ] +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/assets/books.csv b/app/multi-tenant/personal-space/cloud-cap-samples-java/assets/books.csv new file mode 100644 index 000000000..cf08555dc --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/assets/books.csv @@ -0,0 +1,6 @@ +ID;TITLE;DESCR;AUTHOR_ID;STOCK;PRICE;CURRENCY_CODE;GENRE_ID;RATING +8f45cc39-df65-4790-a63f-634e151da734;Pride and Prejudice;It is a truth universally acknowledged that when most people think of Jane Austen they think of this charming and humorous story of love, difficult families and the tricky task of finding a handsome husband with a good fortune.;b834ddb0-613a-4edf-8d47-7d80989e1325;111;20;GBP;15; +3f09036d-3a1a-4eaf-91e2-5aa6f50dcfe0;To Kill a Mockingbird;A novel before its time, Harper Lee’s Pulitzer-prize winner addresses issues of race, inequality and segregation with both levity and compassion. Told through the eyes of loveable rogues Scout and Jem, it also created one of literature’s most beloved heroes – Atticus Finch, a man determined to right the racial wrongs of the Deep South.;b22f5293-7eea-49bb-9ee7-17c5de81f1df;33;7.99;GBP;11; +21c12f7b-089b-42da-8416-d5f67606f939;The Great Gatsby;Jay Gatsby, the enigmatic millionaire who throws decadent parties but doesn’t attend them, is one of the great characters of American literature. This is F. Scott Fitzgerald at his most sparkling and devastating.;a57f75fa-2bda-47b5-ab4d-b644570f29cd;444;6.99;GBP;10; +c49c354e-8c18-4022-804c-78025b529fb1;One Hundred Years of Solitude;Gabriel García Márquez’s multi-generational spanning magnum opus was a landmark in Spanish literature.;1d2ec887-cbf1-491e-943e-33a2b4f39a6f;55;8.99;GBP;10; +0c1ffc7e-734e-4c1d-ba87-3a032ad8a5a0;In Cold Blood;The ‘true crime’ TV show / podcast you’re obsessed with probably owes a debt to this masterpiece of reportage by Truman Capote. Chilling and brilliant.;c0526b1a-9a75-4a43-9133-163325cbbd2b;66;9.99;GBP;16; diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/assets/readmeImages/BookPage.png b/app/multi-tenant/personal-space/cloud-cap-samples-java/assets/readmeImages/BookPage.png new file mode 100644 index 0000000000000000000000000000000000000000..41fd37a7a2f1a641ba76216b74617cba4770996b GIT binary patch literal 211617 zcmaHS2Ut^0ur`W_sEC4yNR_H0pp+n?DoF2DT9DoXfzSy>iXZ}^_byGON$;R^2+|=y z=)Hx|TL}62Zu#$h?x*H?PO>?>GrK!GXXc&VIl(GQ(xf*Z-6S9&AeEJoR3jj`?o2>H zn0w>;a#5BvfQ2Bp6ko5OXWA83BPzaBMuWiu(G44|o{F!&m%GEV&0o zHibB2W)PDMu_}oyV`f0YT@CQp=f!inD)(NSy`_44U*F)0&Mo7gRZjq0x5}P8*);wc z*aMoo=W_fD2AQedpWXk}eX3l$kLP74P-%5jvwEOF$fy^^5pr|SjE#lu<*paO70H9r zD=xxK`aQv+w+X*0Y&0Y4g$N!E3)prVk|`#Cc>Y}SU0$dKJxq6ig*^d?wL4 z>P!A+_+(z8J%;^>4aE%{VXmif?8T72p&6HzR`!r#0%djuV*g7l%yF<)uu?$nl$6)) zab)!E^VbA7BpBE}5y5|uyvo45znjLPA0sptY6y2KRY>9LF@p}!u$w|zJ?qyMq+!y; z1RdL$wn#Te*K^RDq=2V-@CP0-KGK-ptfzW%%mmUw1Q~<5;0KZfYitB5=KGXo4J0(? zTOWy7GHyN;Cw@pk@ty=c*rV^u{yvK`=);Y>gycVke-JZ8kea@K{O+cfACt;efL~F@ zRSjQ}_hPTE!9TFsUro6}^@Gx$Zt6OjxWF1A_m8`7#8QkmS|l_+-B}k8jG#6p6nyi% zi{|EsmW(G)?#cNMJtoQi5cj4all<%bZy#JFDhI*`9M*0-k!%EPzZMxFICyk+jrj$U z`H!>jg2II6KWSgxhx@L!tnXZX#lRJSY+bhJ_q=Nt(Emew4rMQJewAK|;EfdDJ?6Ft zMvuK^u0;i8KjtwNR11xHJSrnH_GqqT=@9S;_RNjln$PZEd{mJ^&4 zZuWXBFt5-l$l%R((#2gjx(3pjTMWLd^Nzc3PtYg+C&MQ+C!*)XR}~Q-GhO!^ZR>yYU)t(j>l5OCNdHRtvbv~CXrG(9kO9|iju?n z(FKV)wXgR-tq4xM6#auY<4O>fEY*7_LxXLcFQ7`F5Ri5S8Vs33)dwE+%96t=Rxy zc#+|odj-YV`ab06Q~xUxb(z(fRC&Do2+NSKKPsGeeplLj%`Cv#FEKEBa5YF~;d;&BzO1|2m0J zt#LaL-P;PCX@!Jn=kArC&-VDYhve`|49Lbpr-124gi9wVn>nj=C# z>vC$)_M65p-$fQW7lv%Vb2U7s+-9E=^QiGy@}S*4X&oNp9p3+7fmaAgY)OP!9C=W~ zb{kw^&M@9a^@ir-?W31_^QRhEVWZ^lL|c!Jc;S@n{*Dp*L&zEJ6Z| zM-q0Y=!O@$IUUa!*iwk!$t4nxH<&PC3^keA>O?O>!n!hL-lQ^ux|L1p_AHrq{eVf5!YO z>)E20x#UVy?_l9cVIcU8i`^KFLmu~ zH5QHy-NoA64ZYs#1&GiXuxPsJ$fh*o1RCrmtJA&eeC{0I?08aqUO#wfwJ8Lsu^X?v zSFKvM+sBr!h?O6e+n0w41VQYkTBg(*meFIUdfc&s@tU^Gw(8(bE;0_tj9s1A;!!{4 zm(Qr!rdU#;1DC?-UGKd2t6>IP28Wtwnyi}XO;kQUuC4>y9oG9BWg;~q?y$7&Fcj*7 za5HG~(R5N&5;v9wTX!st7SrC;(u0X(egpz*lvD-mU!2YzN?ZgbZQ5?S3RnVSXs-uR z2BqT@_7+o_Go>ftW$-b)>CrIUpn}8 zMG?!+uVnY?El|_V`oQU8eO}9Ib1w0Kx6yVVMW3Sh3br}5~*FkS&11XR=B z=)8PXh)Q)e#!R8*wl|tMYEVAhn==Ji_hV`L`@(Ia&%GsK8b|Li4u>UL%>bu*m-MY& zOzj!VS+_sP8xu0S)aWOynip)iQf0Yp$qB@a(dDgWyV#6~VR3(v{2W(dBiCilYJvh%bN1FE7cA ztN&el-8qBszsrQV|1^B9E+H#>`KxXMH8Znww1hbMxG-2>vO-#EymNY|r~ov9*m4<} zLX6G0+-&XtAt4ZU16~$w&76!F-E6^jjzBjNrvGRGye$87o12O8Kbkn%h%miVRAH2W zK+PBdTrap@Fp1t|WMmYEnwkUEB&Gg~{PLd&lckfBJ&>E*)zy{Dm6rUD~KKAKYWdhAg2a=qaG|GY0rh5xw=RIze11M5gy*v+}X4wRz)l)i=i@p^JuJEq(-7Z!muN)0fIOBB=b~sDr~_+FTNAeaOB; zcjd~pyW#|Y`066K5(T8*VRH!nD<@gHvp)^xKgJkwKX~i-Zi@B0} zVpkIbl$y0=)@lUe`Ts&2^USv*3iw5qE`Ff9rBZS2wr5y?QvODg{_VdI1rQC%Z-9Gd z*1Mkdr?YVSxcLVt)o6bY`->=Ylo%Vc;qZ}eekADqMQzZg>Fe6P^X?(&fF6sJoI&-H z-=Eh)oRKR6q}CZa(%nrpQAk4PW2K#yLOYbT}g**Es&N$4PHm?Yjcz&GW+bJs9e2~Q;nc9Xso+>cKe*G%-So)vA?YG zrAGZD+mrs0?uiDSzKN`)saibOP@(liwg3P+2t0M#us+4C<*?~wO+4K17Y@nOJ*B1g z_E==^-#VhRF$)yTGW3u@~7FtNGxbRSr*og}HY=H}ICy4(}O zCLfZCi5?&^Df_D+bs3AY;ou>6q-2`dx2BY4i$i0`R}=KjFZj5UU-1@FT%?ofBXzpp z>1NiNVEncCypQt+GcsvwX-urgKy8<=kCj99nFKtmGh~ua;5{LEav}2!Ti*ke;B3in zsLa$s0BXv~T2cTCGohv=TvpI)Sn&?zvAS=&b2Ekf4-d;fs$G>Mo+O*92z6Yovto6c zYF9F>RZXL=>Vgm46SH!78csh7Ter;{q6RSj)uT=?M>d-3G<>X!MjaP1_W=ubP^e`W#`!P3c z1Cih95Mu(7;X`)ph?PcVC|`jVR|~)OysqF`k!+-w?pJeiPWB|LvFnO@)QNA3 zV99M+PE#a&)K1;Gip38F$Izb6BgWKxCb3f`CF+@>2ZDJyPG9vBo_sR`)yubjt_n+C z>}A+ecb{;wdbz^8ADTLFIxXuuaOMN?Vlq6${cQ4}j_z_l9YmS-YyDb|AUuY%I9qEJ zJWHLdjB|liL`^uZB6dofyDJhMKkGZUdN`Y=AHihGJ4nsW+wyr@D)cH$bs}Bn>0lL> z&tTQF>Hxc`Ck&nw0{ZQMKQGOV7@mKO(EL4t?K7bSRe^YPV~DVjY12fGa`3KHN8!6@ zZbvBfsD<=G|ngyxo-NT zIoF32;*YAgp_bLHpSN6vZuY{UtEtu9DHG+>Tz|7I-$}1QhXq#)+ifJHU+gXiXFWnd z@YdV{bQJ}B-*m_1bI034tma|Z8G6xH|1=pSV)iSk<>}FsclE_- z-fI>o+UqudcC}TR;<~bQict+f*M+(+@-}M_lP2gj1#rdFj z^aXIsqi@jBeRSM1N?rcse_S3M&u@e57QhjAf61ANvBD-;4Sv%sdQP*yzZ@6j(G?Nd z+*4lS^Q2WOy!v?R@IxcIPA}ezm7QH$Dmy;EmpT0lVkBREIZOZ)vYj397gvdr z{KvwxS!|;PB&2@n#qKcy#|oa8q)n<_$D43l)!VR6fOF*v%%%EL%3w|#mHlkb<0x$a zT_5u0LsBqHWBd)-Dt?i`aJpehkJQnlwVe)nq3PN)9p22iPsJ5Ub1`aQ*L3~{)^4kdF-I8Ho?ksS&Ng~>x6)wwQc@2#TWyult zEjHd!=ssNz@B1ET_e*BGCR!T0{H)c6g&${8>hGmKvOJ{zvWgxntXl&P?zLs;fZkZB z^{b^04BDjgLLwCs_!PZyUf(pu8LvZ(mD0||=r#6b6T}qeV z$~W8-35n;bUj9t^1-&u4OKw$caKZu%ONK8Au752aDz)9T*BnBpi8MzUwFZuRC_WNF zEjE`qSq&a@uakWJ8{`vXxx_TmdFsO~A=IV&;^|gHdq2~c{m6WxRUMvuidvw57)8muZA9aoPy84bdmBE=)9iX(tTORo!Vm4x`K#iAd7mS?h$(ypmgrt zv$8B3?=^{Nu`7y?x@MKcKu!lr4u~_-&7~$7=2FJ7#96QwpuTeQs4FeAJ>><}`5=WjFCT7J6DlhTxA+<48T4G`M3u z@Oq`ski|a`9@nWT6yH`FCLsn`Sw%4SH$GLKb}Tx_ZK+>E;eb096o12k<>Gzbo$1L+6blN${`BE7IFtJZHgRtg9PKpN22Y=J-&xXvE@vuMtuHfN^nPcITm)4QZ3qq- zYc+?;t$|6@iXM$B_*vu}D!X_VyNi9(E_uY_8C7W__7@OgnkGKU?EGk3O|=fQDw4N+ zj-%-+t32g_R#9^r?*V~fy5+j8K6jLYYx#V$pFT-_qaeLj$iwWka?pPk00(mJO0Q(| z3=fLfT~q$%GV=J(nk~LUk{v(tvfD4d&x)c}C{?#e51||B)lQj4`^q4f6VN~OlH?1V zw4kTVne8Q?V~!3arW0Qw?GOaZ^4rp|Hzo&OdZmUdLT}&XxjoeVb1eHoyz15^49wT% z(k5QYZoHjRA$dnJV#oa(hA*+v$>4=qa`GERq&EGeM$!X;$vkoC4KSd8Ad!P}g^VRL z`bg-F#Gjq+-7cqpAQuM`9AiSy@Z3Nb8MRH!7X=S1kP8YNWjbz}Qs@M{Uodtr!}BFJ zSr(-rYgMzoCl~m6Q0KQEM5mO7G&k)R1e;$|&dC4{b{u@PQFzlCI-s*dN0KTjz9sRe zu=+CAEu`$4z?|%#Z^`Y!Xs4GHu(xTj!ZdVcS-}tY6=*mG3Jp}vxp}%DHG_i=0ye76 zYlkM?hm7ZsS)8JpHAns?uDF}o{A!&uuoq<=@jD1WW>$UF2ugB5>uX6xheB=D8ZkLg zRE*;V4k#Xks>sO2 z?Q!YhCkH;Aee~=vK|dpwXoxmneNKc|x>q-713V+TEVtRq>lAn16=O3oOIG{0)q5g! z2@#YQbDHlvCfTYRm`sDofvCW^a;Cp%Z6L`%%2exO9yt9VKIAX>;bQp`!X5H=zOo+0@j-)YYcH2_x&8%!cU*s=fU$Gx*W>OkB;v!fUk_ z@|QL2dg7a6Rc;Oege)yBeM+dDc)`)*X6o%TuCEeNBZkEq_;9~4JN8ai{(#0Gse?s{ zgAqh!(ug?f!`G|Eza8TE1knR7{U;KEw<8mIE#$nty#tuJxs@LY*geOhtJ5z*owRo{ z-^AGJ(#oWpQL&DV@Jk(?#SpeHkJ^|W`Df^#)t_W_%r;IZGWa;}YVMJs1k#P8fmKxP zJ|`q;C)*hcjkpij>32yzU24MFOvyRVSQne@D`w&vNt4?Kfz|zK5{OI}-D+vX1CMLB zes2IxKYU^i$+3a1Rtzgew%dY$e#f^uC@r?2+G{Jaty+&lg{U6V{BG5pEYy}ZfZ?W#&3nOfek0H@~ zzi)SfbWg4lYVrs;6h!oUAHX9eF1^+!y~xlIbR~Ep1Q7S|TX;-xy^b>G}4a_xr{5Wrh703^$T@$6UFl z(sA4x5ZC#;GPpT6H12kZVHE=l&To|P+^pP3RNMRy`z1Mg;(7Y=u7g#N$VS{UJBXv( z2^Wo8n0953{k&T2-+K%3^#?K*G4Ogq)L6&O z#wVF!R35$(sBHT{2FwlZBmWRU;8%XGj)&pW*U^ow{zpe{B1(oF71zvsd{mB5*UUDG zWac7sL;?BHe2dGoe22lj#-hp#_Z}Ay74CARdT$q$c3~HrUAJ3H4kIzDV(RoBArq3n zHB!FM$?Z#9W!?{Tkl?6&-dt(5_f!qP)zc)c0uTR@IdgMPz3jw&DG~UZ*qJV>^0>6+ zaRD8mK2qRflGX8G|9v&?*s$7mqVl-e=}$9_Be8rw(00WZ+Sx(eSk@?CG)y{;!Qbk< zhZfZ?;Y9CxW8aIJ>4UkSIp9ADt9NGKt&}I~XUq(hmO3Ja4Zg*e;_vOAReMKvoWWiQ z(Z38gbA>ip^q!sR`dAr24z~CXVVZ$WX)T}cqR>H=X!4xGx70}=J zhiwYe(%`#a9E;qj$B;1e<7y7vA6eDs)SYNqImn^yMrK<(<0!wE))M_>j zKMwkOhxPY1vWx8s4cWnhAHe+KXR<)V>(G}P5b7t=FhY90cIKp!#}W_TwwtUT4sa(7 zU`q^pj}SV?oz0$KXUnyYtuC!=chEtV4Ror>Gw`ghvhDu%6czH+%;hF<8IkZ{TPa{adgEVrd?uFF4?C{ zO@_YTeh~luj6eCxFyZ;fvgn;LH`DMSTpH;t{FGQ4-tXde~Il9{Loi&1Y%bG<$()SZfKh2<)BJsw;A ze61m$%qUS&mw`g_oWY!!2~}Hj9#{vtNuZfMWk}&|&H?Ubp+RZMU`M z-m4K<5W_h-~(bLIZ zf-YK!Ur|}J3oGf`N8pp-Kj`E0_ly237hrvrMSm{P!$-kcyE4c=KIh$brv=2yck)W@ z^{ABeqlxv{`U!c#>;7adW@xwhG8aGl#Ivu&qN?GA>kKo;l}(LR_|16EKOu&a4Z0i7n=rBs@-~>nt|FC$ zf)>L>2~l}KKLp_dS=d)+fI28W#;5)Yve-xn&F6aE5z0evbwC`_M)n7rD0gL{eFoLT z>nUe=!MLYD*Vtem7{Nn-K+JtyEY_MHRCun~uK0T&|KXn}`l<9{mfO~=@RmrR9b8O6 z?PHn1Dg*tI{PP56ax(9t-&2am-MUM5nD+F3=*VM373)1BcOW^l@Ks+P`iXIdn^UwQ zvS+Y{rW$A*zHi~^-`3Z+=-CV79wzrW|45$qOSC%8M#EYn$9*1Ud&@mC)o{|KTwb7D z-n2EQ@HT3z$u>owf|@POQc7yPQt^Q0Nxhr3!=XoM+iY-i{Y6<0?s2~}AB@Q{E`xUS z>j;d@q=o&A=z-fBm0I8dgW~u#r0rQPXHcg83?|>g8=@rE_T1NyDs(g%FUgo$H z`;4+D*Wte6XNq@~E?Euy_EEGj8|8K9S%;xg!Qj+|UOBarT?qp)?O>s!?Ng0ANSiP0 zS`30SCH*lcRLzpr_Ee6!Na-5|Ykeysu)$u_CZRwFVD< zv!K3w*PJdhBb+WArqa|ZjRhe~5_Wd^hMPqn3HNh~^mB}LOeUqaFHlW;Kd@OtZtRw7 zNLA(()<#zHSglm*MQnsmD`WT4(Gc94;qz3}0aXjZ%s`Tm>#q z8rD~S|21{vgP-43n((K;Y#Qh0$Y!P)n&QhUL5qfUl`&VcR@T@MTK5NDl+q-A$(wdx z$VsYO@Rr}l+FpW%+srnYkViqO-I*_1K~cxk-sQW5zp?Zg@2+?S!j)=Q$XVLy#r-RY zMl@`ZkS=BH!$-O78K?D8ZMSS&hEkH8=WkG*S1I~@zqFVgkYpN-Fkz3x-q?5>{Yhsf<;Gm+#)^S zhPk7ERhx}`9gG~4rgx~(hYo%mGOk{U#IZgt)UTE6S&EI6qvVKN`mQ$NGQJbZ<1oac zQ}1Gs-yq6$^Z!WC7yQ89AraivN#_80gdMua>f=QH!Udj!6F1bUFSc*%ceZee(CeQR zn$PclfKDrj*4fz z?mVFio9$Svjfw6o&ti7wn=7Il@|^U$BSjrvxJ{NB31nTv=PXkVA!iSw3QFo<%B+oi z(@}o}0KexhQJ(dN{+#8GoMl&<{DQzOAWCvjk)2(6>0V85J00)-TjA!e>3M8 zF`mRf&&(>(u2Lv&fW8&58m`Hug~60nH^F)_V~41b-93BHmw>(OYr9elyB8lQ_U^T> zFn?io?q%i}O>y z(|xPFBvrxsiGZz^w;@ZBooV+KxAdL5&GtG9xMhcP6^DQ&Hrd0qrN7zH(UbT=R2U+J zRHj%#6hZF9wxR?g^!m19%1#4x0a=C)TLUV7<#i z6UyFoDC<3=*}G+$mFS1gdab^Ukw!O77n{HuA||ghJMj%hRDj6^SNs}043h7OmL3(S z@t+c-*?lS)mTI{*#xfN$TFw}R$0k;dDFjwc7 zxOw*hN+wUI{vxTM*M4AXE(2I;gCIPfVO{Qtjm=ejB#%2g^sl4j(C&d@e4a2%!=uuD zsF{j%t75#4)>-0{@+ZG(7MP=^kAL_q1-%xVKnu)xXrCR>Fv2SASSh^IpJ*0nM6xr$ zUcE{OA(~6-w8jbzIH*!wi=9MHGBS#ln=kf`>M@9Jc3SSdG-%W`9ubi_RIhAE{b~o6 zuUq-qN$B9N;Q4pEp<>(QxmVLNtH8=>e)H_1p=E?~d6!zLr~CTu0ma*+AlE|ON;%Q< zHHy=2mhO)5bVe+?KAhH5g-UQ`jX6gx$M%@PVBY3E&A%Q(s_$1IJ{#XOj?bX!v!-h& zL`Sold0VWpJ*zp^7eO1>69=E#CXL4Uqqd%%CIb-M&D=34LmDQ-JBg2HXB^KNfXDnk z*4(SKb+!~h58p?_&&E5ld=H$R_(oD8WYK9IE3+$Jr#97bE-`%unA`E7R`c#|tiY(b zPUTXZ2=?8mkYjOlW4kQ$!ppqZXz3uthee`Weg_5Q4~Aa-F0kZB@X?&Fl2m*2|B zYpNte9j>rVmaORac<``ZQgQGCU3t8rcr4I-?a&Q5lgbSOD7viiIIcX`X*3UO46L_n zW{nzfpvsj^gKalVQ=&cgV)CJ*l}NeVUFcF2;d^6nYQ-y81tM;{SHe+_1F?v;7$HP%1dkFnb% z#vPRFdoT05)Z0zh@pyG8xTC|Wx5VfaN6h<0zy@{5{4k4$A*cJRsKqHVi^ZPqF&Y3k z#s*TO6L_1>Jb7)znXs4l^FcaW1APO=4twj>#O{{#|Hb^i2bZ=6sJXdpKGKWDu_Gwr z=~%Qyv00uXPPyl&87n^@C%ro{-f^OSWmmlR^-<~>N5g$>2D{Cw@U;OIJJGBxj-KfB z@XFxS+12OqW2E0uIH1Q`K_;)M$%VP#H+2cYFJ2Of<)&c`tElf!{H%lilDUvHycO)+Q2x2U~b3o0n=bc=sf8p$R+*z!? zS`vZ8D#oajf!XMiFvf=XRNrXU5(W60SF5^fKD##JJ z$lJx};u#p-#;(l$S(ji&G(&B!^kit(WeaIw2y zRS{gs#Cr<)ad^@FLdCVM`u>?cgXWpNT0t#E7n_+WC4=LMRl{6h3h-ZmOGcgXhD@#{ zexiRkN3FfgrKe2H*_I1Jn()xds~vy6yIuKqj5}NAUab}Ef*B{T!C;k={oNHYS!F)) zj9V&GHroVps+;@EkX3!9C}J41&Drn63$oVc;O_V02hHH@p!T_mAzFx{k_#pp0m`lt z-ni~8hR`x+o3T~II+-U2nb!-op5^5p940J60&>zK8f1>H^Q=8x{#gb^OQDVshUPsc z4Dh&WVvl|qz^-2HdZnT1MOo#~%>V(u+{&VODj1%PL!kvdfw)seLgyvYi21mZ)YP;% zUZ}9PCNdcbJiC6MMohq+))s=wu`W4H(>R>D0bei-KXIOGjP_WW>`nJRAr+6j9f87( z`xDoyGNs_s)=$*?M(F$ zuk#BbD3Y%FdN*V0H*_|I^7mD05p!_QzO(3iA3ZT}+oz1_xt|hSM?}+jHu*TNSelm)IKXVlNst%yPUh316}TM(Uaz`T|6T@@7rD^{ukspe|d#wXN&;+ zdAZWN8If<0G_g97;xJ%01UUgG){i9ToAw^C?t$>KdrM+uQQ>x?a^3)DDfmo@gMHP) zhJRpb7!ljcmovi27F(gLF82qP%>z_^ZBS+#4C_`cFZYv0$t#1IAt1*DPy5A4=wUhv zLCWpn)8-ME2txZ~8s7y1F1A*!juIA+Lqw4$tqi|z(DCL>{RmQuV&`6GVonz|Sm6dS za~~uz8lc?OS2oM7oz?|Bse&NwV0$N$UscjG_56*WcWjx@$H_}G z*l&JuF5W9EO}STln_{~jS-F9cpLIyqD(&R?X#!e}nT!7sz9Rtt+`<-myzW+0#<%SH6W=<_)?+l9wyg{L0>{Rjk=Fv*a1wPtAy>aD7D}9ZVuLOsyIW61ddYhNz$UgKCS>>7ASHd>0IoohySN}liaF=SUkV?wXsoe-XJD#0xWOe$$XWApa@ql@_j-hD~=(;i#{K3lFiRr*e;?P5*t? z!TP}d%9bf{)2gzG%g;qZe>R)m7}Ju&M9XNPok!W^N-dY2m0I2o9!sT-fd`l19n@&{ zg_Em}CSF)fVT<%Vw&;JBgX2!rzb_}Rk7yO|=1LdnWqnEU>D^Y#1XHg!bQZg4^i%m; zjI#`^1&1unI39;J2RsMW_H8?^4zwf&ZL!r0d^0*`7|t*C6afd)8c8j#9XJM|N5yrM zfL?LRKKs3?6u3DI4u?%Acr@1huX8mhGXMb@;>9qPg9 zm^II<%+6gWiTydpSAGRn(iugs;KuI>v3<-l9Qf(;F5pb!g>k2tp^lCG! zuu(0-mw4Q9&C&V6sceE$Do~D<_hS;9%Yh*95-LS7{L<~8u2E%%rLl$4pj7#&(tOg^ z?t_ElbSteVr&$~Oh;C8!I15aH!yEUj^d$3CIPCJZA;^qwX-p#>I7naw9-#Ct!1n(- z%qj)(MWt@34NK@8>;6>SBAF!4B;KpX-tFHGcp%&gZP zB&HC1bGc{yTK`Ymjdsv$aMaiEM7izETX(*9XSn$@14rVqGxThR=R6Ydsrt;Am&`!; z+V~HJc7XKt&@>KiLubqLh>XJ05L-bt>1b`@ZO}sr63{qU_#pB)Wm&K9KuY`LW|83+Z$2&sl*bRM#QQKl$0}_72m-`?+b~aaYb;@&p zUYrDa%f>GOop09AKx(IzW?eSA*(X%r>^ibN+bj<_&=D;_7Dn>8oB1uNf2sO+qJys( z+uYT};J&@-np&5n@&cu4`6GydfaRC&H2fhg_hk~(b269NSvJLDpF^tJ(@;3ipaSw} zCnyW77sgs)r^0OJWj}PEraHAT+>^&LN&o!dc<+}%r)+J5zEJ99*a|g})J8L^O3|iA zT1+Y0DEdJcOn}y^|G;8@E1g~R5i|buea!h{fQaoIwhMCh1PlDs{>qEf)pD_}(G~jm zqDe-9Mo~%n#vKA!GhGt0irFa*=b0kxVMPV2QEGRYX~m&kkX18|t_!Q9mnR{ovjDw5 zk-`(PlxcJBrdH*`-8Ox05SW}B07|k)v)VK5j<^ZYgeweik>@EqXf|#3_L1~--Gdgd zCw8=Y?&&N>RN{V|UzZtccFtC^pM5&{F}%9=hz_gw7GJh}kGDO6D@!UYP7l&N%%%>o zoixq6MI$yZP&*c?e>$NcTV*-8z@#3@`EE|cQ#m~SrDJXbt`Am6t#eRv%SoqZ0M-;* zFk&%1QlzJSQ2S4UPqjpyTq2Jd_)ruE^GV!2zr{TPjqf9_Yt5Fxy0~BwB_2IwVs~yH zZQl4QFzX>bBWF*#uD@E|-~67`$*Ip7sZX6E&@>+fLd0>CeXBc_%@f*g>KC=>(p(#X zY8$}(pBvQmqK*G;fqlfq7r6m1lILhIaj$7QO}Sw~O8^`&Y}MEY%>LLgv+6owdU5yo z6uC9j|lO0tJHk9)a|&!?|tgr)G&a6 z0d^>;T;q7jY#zraN%qg+&t%eG_O}ZfHMfXqO&3^k3TY-OQM#HVr^%ao)55HKu+_Az zi@BV!{>5hsN;O4!d_1yWq$(TN7Y{_kCy>eOOLJ8-UlRy%gEG@V{`-x^rt&<)rsxSn za$ozY7n$5Xpa3U9(wobk=M5Ji+kXt{J_PE81`b=Vc%qRywwsD6UMsa5OVW zhGMI1r&2Kk&KL-`N3nW_Uf&-sJor{ReeKJ#HpmmCTd{MIwGfyLi5B(3PT-OT1_p)2 z$S&HeMor)%E0(pGZ6UDx$)`x@uGocHHQ5F^)YTNvvFCw#5G98kIJR4n2 zml^%0$uhl}!sDEj;&5b$K6U<9y|c!A{6%2aEp^K}N<~?8S_0&=Z!5&AU+{oaQktXa zawoFR&`ovc%(~1Rt-CJvK11ZZOrAR`gsb64>gRtSN`ZaF4~GpSmloAuuce|wdH9NX_@?J%PZ-+&Oj8WUgJ-t(cIxA+oHFa+7;@Ot}?Rf zsgtH->2butWyGz)um=(>eD698ucAIl&AT<9D$VRM}9 zQgxp`-{jcxR=H(klToH~L_!FfZ1S{|c-c*8L&Ucxgu@~;TyeinLC^-necirGpBVS% z`PoIHvYlJAZ0}lp4x9A>LIYLrQ4hfSJJ-yhXTclt-OvM7=>&@jjhJ{tSSwu1p_{f* zSaCq#$;j1erclSe5()D9_*{TllP_{lvmdhMZF`)jt`sGYcduR3Ft=MD@a7i0s4-dE zOl#cQcW`oo>)mP>CzQgRF{qC@;)W0@CIPVUe$d_4c#4I^Ix}_ZZ?rCuo zO9`c2L6((Tqg{>dH}s>}##Q<}YxO8#n1gMY#bpNBhd%G`CFh-?ALLx~HA)K`yjthi z0sTK*N?&Ekj*Qoscoto5Ks7g7U@Y}VA*)CAmF{2RwyQmby93_kL^wu^v%(1v)5zPI z_rgqXUnVV(;M!;$C@}rNz1$rfuU=I%%!V#SlE%V+*v8=>r~GiU0e}xhk3W zHt>;&FSok({P{w$m+23tf{~4loR`W5S9@ERxiBS9xV_*G39n zOjcE=#}DzUNjL9Ls}<`DTB(Sg`tR!t8E6;ij$Yit$X6M3D}?0YtB#`j+~uLE>mb9+ z*Hodfxx{B;}uEz3c~142wexLFtedUN+IzGEJfpr_s7FwI=-q9hIt$ z5VRA!JbRku!iG7?LcaIZizhZyB44X%GWQ;&h(Sf+)jnMeC)>jGfc(X)Ge4;c7zpyf zKtC?GH39W`?wQd27Z@X5BxDx7FbffSoID%%yF*oRIbS-GFAYf|W# zmCBhI(!Th;LlhyKZ1o*dwI*T>yWk%W+9V97UKpKgw8Gnx(L#{}7PlH))s(%gqeuxLy7hwz7tgAjUuxI^%OxIRt|`hrivTrDrHrVdrA`IVd$FZ!cfD7@e8wEQfy{kNOmPf?O}N5t4dI(15G z20?GfbNgnc^(8Q173e!=(D0234PK8#(&W7RE=S5dL+iMyAgGY4gk57wcEdu5aWsI zj;ITe>NpG{obcn!u)LpJt?ZArsESK;mVH>oq{{$NrcSrV%MLLx^^cVLdYbY2 zf`@q<`OSoRn#9JH-#o(U2-WL+t~V6Q?zHJq{=X5*f1WjWN%?Yq3a_s*YB~AxatK$) zQaI~}T=W#m$&=^w5WrY?gWpIWt8}n(ocSID9?Yf>gF9vD7(V|_!3eJEJXaYysR^Np zJ9sq-OT7_PL3>kr!*bu=Je-GKXPBX(|IIE==$8xE;TN&ffj~x5T=)SB=G<7_1;lUHSHegYeg*ZA_^iUC`b_mrAkXwlz=n= z1?eii_fCk4s0bt?VCbPqQ$TtRz4smnO?nNT5E7Ey&3Dha>#k2d|F{-QvdNx3d**q5 zZLG#7u#GAa7R{kCf_Z_D|2V9Vqh5!gZW!=?0#%eHmuNl(ff@H2u?>{_asg%WDe$>b zMwPoKGUWseSvZOoqi;lz0x9*OrlsX{U3$C~jM&NCqk^pKpxy%IBHiURxDD_(+k4WO zx2T?ujtHd-?2i{u?4u?OOH0Uf6#3_;&mU@3aQS~8%zh?r%|3Mn^73ufUbo+NV=ANS zXu+i3gQ_mjts2@iR6E1dp?ogo9CPAh=Eo2QlFCts6#Ea(0%g!|iBy=&qfA+h<5j#mk@FpTt@S}6X%-;s8QUWHy(ufaLEegHMm%rnl&?=K{B6jH|tn$J_+9D`@OuQ{ur%$EBKn`ln|%T@Bfft=j0YfD&^uYe?6lu942sE^+^ z(70%-=INimrP__mQ%=MOBzHbfv-h=3v&TJZAA~Aw2K%mkq$Znw%!Sb9Z8)X*!q;3T zUvv0X(VDLAdeN#TFIf=2H^jTQh+3f!topQMD}ET(nB-PYTOLfe-0#m<^os#nnx&74 zg+1~-WxaJZ=fhoU5T)}NTyX@2Fd>&|SZ1AkNSxIK{2F4*o=eyIE1q>Et?vg%*aLg~ zmm5b+xNGCfi8QqsF{$b8COriU8if$P0l#7nrC+wbmSBrVB{!G{+e{@>OzM0tI-F;d z9XD}XJi++cjppjvI~SdbjI=_-wOE9oTSHfW7+30^rbs;JQ%@8g%GQnQPGF3*RF4}W z_?iONI6Ql1TTX`v<~f))BV;pR$rz*HmwPDXk|L3*r&$qgwlbK-S=CIWuep7ArT>4k z0NQ>|^OyrvFF|(Cz)cMjBj%AE${}OG0L~0Ke@La%&wmv(x^BPWgxh7?-s!0svB66) z4V82y_6Ov7763Jh8w}DhC#YjlYS|Tv2j737o>6CKAuW4yO~ zxtEyK9I`gk!WvjG%GSt;Ib9N81b*hPjm!Wqu{Ktyk;^9L#*ra~R9#yR)~MitP9?T8O_B+v?K;!WUY08N@mFn|H#| zJ|hHy`X%pqiQ3 z?X?|IWwi;cFNKAPg#BXorvSe&(9%&cJE`#dVDB7wuT@zQ*?87LZkj-@a zFU(6$1>Bbv85};1(_idJuSI~{s`BB}VjTnJRuE3JfnP<&d##)P2m%i*6{w07;7NNR z>x_oV#qKfu5(j6oTZ4M(T4CL_^4!Z^09g4{ip_NkoZ4<*GvZ~AZj3Zlove0QG< z6B_%@5am%50$nI8d-=uJffYQ-$!elwy2R$`(oKv8bksbowYvWTh6+>oPml+h$A(6T zJGqzDE;4K4jpHo&#-manq5<>l?1Kh*jp9`-(}G3F8#Q^xtBeU!!c|L=4vsb>Ki>!& zRE@BBREXi3PgIjl+#9>%%O^AAidTor7y2jF3>PlSyQyO|B-80RjSbdH3_ri1XE@_v z?JCft$q?kpIy$)A!>17|41=$V+I2p)k1YbsZI602BKTyp`K#O|u-|~s0T`fdggUTM z-x;XC6&1!V-F`e`t)EG)qB9OMmAglpm{Hqh^_p!CQzHlE-Yghi#_jq_^v$x|>WRM7 zaM@udT4}KMYyN9oE~>!CVt!uFloiI;&6a_-1m_a;ROi}v zV{TUrW|}AzK#YK{!2gM`*~NN*JAZhnlJmN}U1+luOM5DmG%pV=taLfUIyA+}A9&6OXRk@ayG!6&t&_v@~ch5?Jah)3a#vq$Z%Z2+$bR zNwNP)u^V$OX=}^5>Xw!a7X(>~#OjEIntp-*!HlJq9)u+olmb;_kvi&#u z`YSwy03`*hX}~T11aJS|hsZvw$)!uyq)v8)o?<=YYh7{Dh3KwpiXTonc<>x{^gjzl z->!4O&7y>jZ8vJ}pAa4GuZGFVP)E$(N;xWKyc25cFH&Ll>yed=V^6*WsovCkR`p)& zPy3Gz^Ur(^2sj)2HG6F){A!H5&d(qKGMU+!1C=OIo7l6=WWQZ_N~Y(;r$z2XtlTKu zY)zuRsJ2$!4S0l$BkwYZuF=AM2S7$A$Tz<&Lh-obN9f?416I?v>IIoQTaD@+ER~}+ zt?t=(9Q6E9#&ffpkcbn6Db1Vjl~Q>tQjI;cED}cxl`MN=ctTi3nbfP73d(C+K5-W5 zRZ4A7x1ig}pa9{VE(!aibsxOJ7c-G;%=lF+wYgOqQ&X%{i66?%0iaH`(*d+V`;njb zC0ynck>YN{_JXF#RlDmGEeM>Tvg?KQFS@x#H#T6K;hb+$vB@1^Kd*w|pPmk5t$L<# zp31@O8|twVU(o?qg(JEoY(;$LyTh$>c)Z;sdq!Mp+H);Wc2|?vd0?bH)S{`kiiXVc zLwy^i;~2ZdKDTw#p706v{!f3@niigv*uG3(n<228FiPP2Hk(5c+p-YtULpVMG$niR zew^DZQ=vyV^1@sCaYH)!f;0$`;%kRN*Xf1JOe0J>MNgM<02_lgRxL1HCx7{p8R^FI z*X{X^j>{;T4&XH9+o&Q}%TLVe$6e}MoG807IKJ-6W2&KWz^jk(4I8KZY9Nf$c`Vzn z?(FQGdl{%1stinBbyV;8<&lgyjK_3&>`2%;xzQxHU zOxfc4A?59QKOpW|6Zcrh(5@Y9g<#Y9YQVR_k_+q4Aiw}McTxiO8)7hckPW(YC zhHXAPD@4OAJ%rEqaluk13IJi#U>~ayI9-A1RqJ{sG%P|uD|K;@(w2Vroay)wc0%BT zyFx3U>n`s5)2#T-c-a}tq3j{;9D||FX&Z+;qw;<}uW{w;3d(skMxzBb#%2bh4|x92 zVZDI}_ohOT7ZXzLN*k(1&D4Y+&uRrz=T}TmjtPG-&CB~$I;5WCwdLWkB0YSe(z|j^ zvs9>H_^OwGTD|C#8aI+RkB1t+voU|wFaxuQohdyk3+eldd9QVWn!MqWE)v@*X!8KN zQOpa#ka>Ap{qGQ5dQG9PRU&&`7S;HZQym&YO#BMmY#&&vUX=Bv0{4Adr=c7>usZd{ z&b_7ZH*67TmPWRYU#06=AoA^_$~T;HJ=Kis?e^a{?^gm1lIY^hFwwjQS&bD2%xqBd zQlZoHKlZc&fGXZ3x8;3DBRrLh_)ww5gVyRMT8j&8xklzZ+gYlXy)TpCOG$YpIB|S` z+{16V`d%)>e~I&seoPuXYkl|x_0Udza}I~Ijt7tx(xyvpr|e2l%U7R=N-JgeNiF<^z|1yR(D{cuWaD`i~lu0W=K8e&t2&4k_o17o5b<$LC zob3?I}C^L<{`sa_C=l!$wVy14| z+u3G?u^fnc3(p!Bm}Oc{+C{!YBiAS%O$mR|;s4t!Dgw4`cK%oM!j0FTc2cN}`>64* zxZ;k>3^#y$s+S&+Jz_89EX10+*x-5gPjJ!E4eOpg85}z^Gb`n)?60u)DBv0nw0ojJ z5_S=+(^7p;z${(#st-?*8f;VPSK-bcBdkaNj}P)5x7?|Za8|^%kX`KTCp%3AlN-yX^d!|> zA8U=5bVEoX3;7~;B4-HoGjS&wbop;zMB`1-Y%1TEtGurx-x6iHa2Gluc-FBL$Xx7T z^8RsZtQc2GLmy~u@%rfEeF#$cPbJ0~?#~Iw9UIjPh%cTvJ=nKt(xG@ZB_h3HzKL=! zhqBnN1XlA61NW%|@F$MxG_q@PwM|vcH(UpB!V|_gGEa(u{cfF|<{g1wt4r z-)X|C^lYG!zB4%=|mp^^}z_jjt(CqZJDJ0fNI{XIoMu$sR=IHPfF&YnmE zkLx&i+$b z=Ek6mx;CytDcI4w?DdyNdGnXj z%q4bFsbtdTnZz_a#ZzU~YunonHz{W$FT2JZI!G^Ona?EaSYy~C9tr%b14>ZrD=(7- z>(4Z7Nc~}zJ(^%9Z+Km{uWuQ{(=_t8Or=x!+k8S4z-?!)c*PsCmRFCgYM~FdmS3c4 z6r4{6gmKfMpDnp30!q^-J33{N#H(oGt+xMT5olEEF1za#PISD(<2>#nD`S|#q;Mbh zg-Ku#I@|W>&}?I%`w56M%j}=)Y?vpb>x@wjN}^BGC(Vfuj#fXh6nM1gusa!2GxV32 z%58pw3`WBnN*OvcQy*Me%VB=od|tZ1>K{{Hsd z8_hu;9`c8U_AWZP*60jxc;Pi2C_Cm{iOe_5>vXRXKeHgd~| zPWC4?`iZF}Zi^v#rM%#n^}WkpltC*a|0$rroV+Xj;9AviwMEC^tXcJQ_miqh1V+qu z4vb=3_m>34QNg5O7GsIr=$l|J_BYH3MI{8*bKRdRt6ft(i&{2;yX-?@EBkOdA}=f* zVR@!uv$?@b*gbWc=P8m(HDGT-&rON$J({9%{$ln?M^y7qGs)ua^H}`P zrR`{&&|gdQk4QTpAKF?Q@vo!si(mFS06%LLPKDjg-*V&3nr&grQLLJb!l=}L;@Vj0 zlAYfgoJ~ER4tfYM7ji{B6*5Z#v-vszZSXNMk}^d;JN+jc5-{lIsjpQBFR_X;hSjQY zY6_FilOyp1Fv?6WlJuj)3lQ57#25M9?V;ENQJytR;vN^P@_kR#edJu>VY`EBt z&o)x&`qZ0_3XfIu?K#14_&FAlaa+AzVuYsZV(y1F0PZTq$;fCe(DSZX0Ue&ksuIgB z1AB6BAR{DJ*YD~dR*r9vU)Z(OFjMaP$b(}9y0Zm>2~POcqou=#qP>Vl6(}}N-D}U9 zy65j%rFs8;-!f3u1SG)(OBkLr{DPx|qDwOO|W#l?ayIlUMJ?ds#j8(h{?Xcy> zm$=n=`w)r8KW7U?t0U9ZW0hMN@D2`LS0&Q`)IdAezx-s*XmQ~g-c_q&+u=wznlHkg zHf9>3J@>UO>iq@wR*_=c8xD%6elP2u*q)LIPuVJ-8743`Q9MP!9FXp2<~=5se9v5k zRZfteM$}y)iw(_0Hor^929iy-WN`Jtpp~t*DymlWQa(jG@h3g_=P6Ht$pvp%CI^S< zKEuT`lU^i5iriiJxM7q#zH_tGO8HWo;}@?1Q;!WpgRqS#AOQ zHNjMJs%k($^?A@8?O16iJ`YI;z(haUxF|F2>sHO3Y~keJ zLbJw}dYtXV_>YyM&x61Z0CYgeZ#};Wa z%>-i%MD|H;N5|NzqpB&VTT=kbmL>om4u{MGU_s>fyu;GSTZXz^Vmj8G{l(weMv7EO zj6@B`nlW#e^YXhX-q_uok?=iv5qpm4hv;q7?Kpw_?H~P-@Y!Z6Dt%Zv(D^;1T z;vIQ39LnLyEYp(c{Au~z2|QtUS$q!fH5Cz|DSy9uc>=o78NxXRI%Mw;1k9(8()Q%PIUhNuE=1aCE3tCwyHM0i+q+69 zuQ7Ltd$*&6_(f|-6-Lfm5cAQ3c|H{#Za4K5D69HlXI#y_;XG4O=1%KSMhNvO5RhpN zS6L#kmr>^{+Mq>0_@CkJM_+veHIg z#qKL3*Q{HV7S0V$TCmC~OpW{OtaSm*+#mrZlvh5<=jEQkcThAHO5W2OQz8!)OOFea zLKB{S*A3zGPLzTz)Q3>7$)>2T=2a6;N1XBP41L%gRj2sART4YJ3ygNQLL%t*YP{C- zvU4yytS^U2)C(CfVz4-d!?qk$?aQ2)MArk#m!=A74J;slXr%s98hJ;~3wZgyW15P` zjlD}p6X~bC%1rhv3%r`O_uRU0#h#H3(fP9vq4=egfuF^rZj9o%&5`(kRErfP-wNJ#!#yrd-i`0O2~#;{-U%&vZcHmBa_~`Lifk7?fb1cH2 zBQ)eEC)G?6rI!j{efzXM8q%Yhs&v8O!5#k$bO80+A&`Mmj{h1rHyDAbChq()RjWMS zH#_CC0b{%48Y#a=O!Wi|#~d3+q|8)^Xh%L2bVEH(iXM&lP5lc{qhsgF?!NSYs8P0t ztj%YQ_<>o+HVx@C&ob_Qs3LN}A{BM)W9~t?Mt@DK=cKcFkOL|jLxslPAp$-<*eiLi zrauNi$is5$U+B1eM@*V*#iL?HNWu}TxtMmxRphxINRMNl3C6&(EA|#(2F#yl6So@m zsDLmm`~Fm4vL*xmqv$Lwf%QWBYJqpKw3s!ccyXK|VPs;=q!?EzQi}FipkG?bO~m-d z#4lK~Dfot3n+^mFQ=H(%(y3@6V~Ow#AmOVcQ!5qkh;kl$OSo1V$|m0JIGp`Vr&*KO zd$}W%KrT(AfDm@r_mIYOf63i%jF1w8~ds6Mtjzg@%#aAMF+io$dnc3 zgU1Ps^7jmiM%2HG=-)KmJ8YKUUwBczkti2v6}eOg>)dgl4A?l~a(^$9UrkHD#ss76 z04V(ew{tyK9|NS#+-hD;_$*S!;HtEZuv67uNzTS#GOQO7)_Li9%}Y$#+&GoIVU}UD+u3t{SJ*?I+oNb}nCwQFsmRYmUKvBXNrT+Sm+k&soNtUb^znf{e zf99N&a0Hehw*WF-j$r$iw`&z92P;1By%Zw{Qxz01>>H z$ax{%R<9}A3y}6yKWO^4&9-^@^uk!$%ZAh2BMpp?zw6%0X$sDWH<{_c8a*$#fjxX% zNlZC67o6eSYT8}NZJj<)9t1TzdD-4Pvep7+#IalWl+~o#{~&Fs*be(ug_(bJ@vaR# zSXBM0^cVk~^BGtZpKB&Jh91y2UXNP)L#|87o7c_E#_@f*l8HKjLm-o~*VA8+AgJ9r@p*WI5*>9;OiVdw-0)mG5C*qP{5kI2k0T&c2ExG6R z0Z#`V2zI@N!y~PVuzd~?hA&SovLCeEV5NlXxZ1POua*1R$vKQ|F!P`G`qs1PlIpxW zstLHRE+_CkA!m^@YJO%DbxxnAEBHfwZ*O*tbt5bf-@z9mT2XdwZ;rJnm3N8GFqJlk zyIpKq>)zLis!0!p4)4-!2&ECJIY4XCPs4vm+dUldz*e~Kgkjr`7PN1AriH8}UKt2a zN)yVo1JEpgIoc~6tM?cxHBYQmEG?Z)kj>GYqW15^O^U%t=PPT{Anv?Mz@ph|rU|}< zhHphx5lC^{)DNIG0NPgdy@|6*u9dM$upy7`Nl)CwfoiDfs6)z^jx_Qq){fX>yZItW z!mCvpY{;Vo9YAY9x^{U;x9cw+cJcWYe12#6TN=!pevx}sRpwjTRV5*Mx3yaW0v^Qh zv@89CHJw_kesR_gn0Vk#}4$9cVK5nPT(R9XbZh;6=K&CBn3Z9ASBE>D>=12!dv&E5vr zc}Z-?(jBw;6(QO!NxQ)_=*O>4f<*MIF6H58qQu?0jl?C5r{g^x9i@hY7uOoT zxmPZg`t(uP6ogvvSexcuSdra8b?q*E<8EF;+o#)MDz`g=GKB01>N_`hN zzUEBkYeJ!V+;)V<_w+p+s5DLVdg$*RIq$`#zEo(+gvvgr@5nR(**H=7CL)*e@O=*U zZY53lWf){-W~Qw?Ku*uoPNBQ$mVQKrGv)e_?3JupC4rwM=pyda_fQt^cS^s~{2>Dl zi|}i!DA#mhQpYtQUwcC_O9*0r%Dd7Vv$}8Db@B4uX`^jIqBK)sY6Yo+JtzJsJ&UxcpI?Ry9IUF?$I8Oz0D2jPPlaMYh*lWLDG{slF z_atSUYq3;S8&o8{Cmek0$c;!s{)t}u=ZzW=l%c3TI1+v(;BfqFS6I+$U|A{%iY0sQ zg_l)^6n0`xTYXB%|IQEK`pDD9!nO=e#%z| zJ~04DWS>svB}U$(0r@Fa3`Ut$yhB*c@5S)ZTlM+jG4_2)ex*Y!_tKdwwCk)ltFKOS zjpZdc0m^I)x39|so{RNtk5*FIB;+4AHu%q#F-Zlj^iZv?i2pv}kEG|yN%xXxgYA1j zPf}n(hYgNR-vQIqiZ!(yVPRa%(NlYX&)mms23uOQYtef5|6%^)v^m48Q`_7TOq0S9 zo$i>z<+Sm+$aA@BGq74*AD}4gM#g7ayNmn({CH1L$x>i@2UT%c*JZmn9bzjvT>w zdjOBI5&FDw!vzX+KY11it4dh~@qJ_Fo$K6JyM_=gH`R;(3orC;HnH+_ zDkgH~y_)xi0oQwXUotRLhd1JikPcGQY!!rCjQKO@!yR*c+B+lhWtrNc{0ac)rdE@o z1Rx{oI}_xe_EFJ)!C?(hNM`h3KiufU4vjCplvlW~#<^47@zqASiFwvvxpl~@M*aUD zz!;({tQqB%0gq~u6PRCOXJM4Dce;%Qxp)61{;%zl^D&r0rTf`JO}oxhMxo`xIdQZKOa9; z7fAgV4jGZAhyUe9!+`)cZi|_Dk-7}d>SU6legvPoeYzH7J=ebgS6S^CjX}xRH7FRR=Qk!eLU3&qJr{7e)tdNxgx;sP}ZwDkAuu=C#t(4f|COg8m{-U4m0%VoY<<>uVyVxC5t z16iwgcbU|kHF8I#stJ2 z6&`xpn>=%Z#umZsb8*^Ex??2{D9F_Q&%s6T3jSA!bHmWkP%${$c!BnA3BvdLYQvpz zFTLzV0*c%-n6*Qqat1xG>1)XmdaD-KQFaH3cwV2HCNJ@Vy={{;uhwBq^V&P;b_-Zy zy&w2&fa?oq+;DrlAfs~WEd04BG_nX*MVUM=vyiE{+O#sUEN-#0a5Jk1HrVmzgH(lY z*Hs@P8rilY`Q2h8QDOeO>49se)Shc6`>c8Ah_v=Ou`1FwDmN00@w3RxDfcGC%WUJ8 z?ugL_dXD6y{psp<%h=Mqc=)aDB@V1OZJmXsSF zU}CQck~9v5d3J0u^R=fUA=eH;bJ43x)LyB%c3hp^d&hML_cf=VBIwwDt9w2Ce+^t@~a@ z@Zu74RKhB3BL?-W{ez6FExT}6_oh#cdD%0L59b(ya=+M_gT&m^;YM5&2avr;+x4$oQD7F~(# zQe9Exy1I#NgDbA6`aj^hFgL4&8+jLMa*0M7VSM*QM(1dhJU``ZtYF$_D3uOf{-Y(9 z`3kjocHOqG^Mz?XD9TyiT9xsZX7y(UuZC=w$6fN?8stbGBNeYojW`Tr!N7kfhuOTE zqta2Y#s1Ugg)@3)5m#b2rVH2$mqNdLtPV?>8J9g^zABPD@Izl*X8U7g36P9orWpj-iEPoF+*WuKiaQb}L~bw>i?GyQG_ zvYTU6)dGI36m{Y~L)%D6N{X1-#JcXyx0iX^3TS zsTZ6ppL03TV+^deni!P6I|I=h3Zq;9(KpuK!#E5q66 z(K2?PpKteSam#tGoo|ovEVKyOw@<x7tg%ljc4tCdCBLJ56{Y~2Wm0pAbc~iJoH&cNzo-hmo?}{bA6Md_ zlgfGSw{3=7^H`WrY`RqSmAJ86Y2Wu}!zEYnuCR2CSf-l+hy6`=9FDgk6`N!@Liz!x{DMphGf%Y2qMI>q^XA++`eoQyc%Hs!Gq5ZO#U*a5WNjb87 z2Rz}xQ~IWdMI_u|tfVp}fz=lj9>!YMTd5~{u&kMjVroFP`*k>`Y3wX??U?ZEG(>&Z zJ=L?-=6>GSP%>ecO>R8~B6}8^u|83$f)z1dTiry%x;~=XA8$z6gedlm)0YYsV{a+a zmrB|VN8+a4s{Z@FE}`z#&CXg(9xS(Vz@Ba5nWsu?!)m4X)Hu8TwS}Iw*c6!6a;4PC zpPUHrZz8!luNHaJ2xBd)fv#1P4pZbaBJDLoe3KD`GF`O_O&o))f`hRGD<2G`Gex;~ zdUw^>@M{r1qiQDrHy<<(#c^J;e!1A4V2k;dV_1Uo0K(vT_s938$!qKwh38}f-h4CZ zzH99<#YfPQIq@9v9v;_$Nd>$g>1o;w@$*KkZ5BVIaW6 zb8gSeUUhRi!@nq)#6r1^|xYpn1 zR3i$4$wP+gg>>UYX*X0+89Cp(!2OO%A6a!Bwv;|C7aH%PQhjCrt8-zUNBSNNi<*VZI%=#l7lvtbbFl6~*G{_Zs#yf}@6GH~TYU=(!fyEdY`I@u5eJIPUZPW_jW`(zB?i%H?C`7HCH@%YCjPRPOjAZz~I`)3Kms7y`lGU0ywJYzb4hy($~$$JjC4CK|Nxx z_%pq>9!WFiO+DN=6Hzg5aCcJqFoEdjFtcHU&Ps*divN{Af%SNp05qYQkW0^K&h)5} ztw$H7r>SDpVG9 zP+Vk}kGvETkeTS+8SXk#w|wHDOD$zOgf;Qjh6Y+NuZsE=i`M?WxOWo^-o`11OW0Z^ z+PL)vv8E}+nqUZbf)i5lw?=k#?PD%VI?fO0XqOs|mAOQ$73+1Sb-xc|H+Hj`M^@X6 zrUd;EPkj!o#xZ=QiR}3iS;qbcNiaIxoQl6s?sj*AT%lB-mUMY~qJm$mOA8mXgx>;$ z=UY2(u0)K->;>#8m7JtwqW?8wfP&QV_*K(g==jNF`@}Qx-Wa~O4_w+_z!cv0ihHab z3&LG~=Kl<-%8w8wCd2cM(PD8-gCUpJog=rBAZg&TehkQ6pGl3A5u<$??pGv%?@iT( z>WrpGtnGJcu`$a|he;A(fEz(Ow|qM#ls@6-(0xU^4s32kqx`@(b#Iq$Z1E_xJ1pv6 z;3UTH6tvuZx!{*a1uIZ|ony%}D!%E>8Ib>KzCCHA+bJ*jMuKjxS`C8FRWHxPYz!D5 zKe;?4WO}S72q`{MU0>?nu`8T}@gqct!;j z)T`vtR;dlygfCxQBQ{cR!Al-EBIwr!0%gfbp2toW+5RB+n!fa(?J$kRJO~alvc}^| zfak3Gt;*=b;6ma`0dm~%);dcFONOHkw%88!gYJ8&v)e#q*1&j2tABr*V99u{gP{wL zAA!9n&$#5p^n=kWSKDTF54|VlU3kn0>=LcFM2JRtPD1daK7MqkH0VAx&$xfhX86Zw zT|W?wbSke9(`%T+>AHEpB$%Xz4yTsukCxo${O?8POd69iD|FCu`D^7}>tSD-hMb2< z&BB?hGdp48U{jX!oC64}bmdX^pUVG}Ri1(eQN>-(`uJNKHc2=b+__@a#%ZJOCFZY)^fyPWCSXPJgO7kYrJzzs_^sVPFLg={ecHa8> zlJ5KklbY?7rC-I>Pj*;MI4%p1In|JWgMc*NbN;NEz^+KznXi>e2U6afF8PG|n8h2X zsU%^#9EP_OL@;yLU3lJ73BMEz0Dj(I@7wP~Vt#RxSu!XD=?D1-0SMY$gBwxm4{|Q$Q7UD+161jKMdmY1M%LvpZmVWyfWF`{wLm zuCd|4Qfm2j3xxIv$c7ehQjZoORmJMwGHjLFsfv!V0){pV?ifGKdovICvtlS{S8Rv%8 zP>b!-%6&>gH8^F9P;BCs?Xrb=K9=u75$(&p)qyG!IpO??{R zQAk&O=JMgEDywG-RKHmvt+iY5K=6>~ub(I0mXK1iMp1mNlRoSS21YrF z{`bFGCBlqfv|rlL03FEgE)VF%E{VH!rnzxmWQtU;0d zqj$eKSg`x%6=8-eeagU9@xDD-;pC@fh!oCST(t~dyZ~4~N_}~}&W4_AY61sTDqZKD)A zCvGz{J$o?O8t#v?i^Hw+OyOBlCKUK=Qh3y6A`qv`8+e_@2lLIK<;yh3$TuhGS^?V` zpD0HD@ve+0k|IQLGeO)vye+f1Rye-m3AX%!MJ@)&YwjM1#dh}D+@nzmY+_Cb^b6?9 zxDR&1(}&o@DvEi&OR$?>&K43ynbHXRQpu^Q9y2_iyU{&zi*D1;wtaJW0;$wqNMVTr z)_#9iM>F4HS3ba%LTlY{sx;2dE@=fqj$hEejn!iFFnnU|0>*Lf9SjO{FW8*ESRdg! zY6vrQ0s~pS5~=v!+usq(C(t(|XJQOm80~(bNpF1a=Gq_Mkh)()9ur+43LgYLFqz^zhZ2?? zQ#IZsemvdY$M6B_;`hs2kZu48Hum7b9IR+v%3GD-N91lpSqmG7@f>c$=f7 z4}{%yluS0V1%g^*=db#?Z_V+MKAsuqkLo&i!5sHoCCr;|i}Zr`>3E1MbJou~`q~v6{q@(CcyeVY5DlskBaYA zXkg6TRt7pEEH3*;*VUc#F?$PacO1rwx^0U`c^T^I6TSkS#|>704OuUoP{HK-8c#v; zMM3v*JJIDUH(I^tMlZ@%e4&CeG!jx$y~P}bpZ29ZI=4J3UNd&#z3%r?R99yqoG@Bx zg>gV%`0W(XT1P;n-rIPMRL<%5zgYnG_03H!#r9vv8r3twTo6rDr$Lnqs zxR7wV{nv)ZXAA?i%8(c6=$Wg!cT?`Hr_P$-=h^j4`5FkIOFz|o$br8+(pd*46PTV} zV3W94?b9_69MG40-*|s|*b4DqINQ;WPvFPz#~XQReI}MsH|5nis$Y!lD^X9j;AhJ1 zAs9b;a%6cpz2xG8Z5;FW@^R3y>2CsA(oT)L8pLm2E+&5c{CjE%PvMgoN?dWsD}%jm zW^G+9L6|7z`)>8Go&~+*QToX5D*8cdZrvN-rsf%y^)1BpcP3kZ;EN0L*A=1f;$5~~ zT(=Ia9$P#L>Wr4;&xiv1Wu&ASf#KcDu7qWNoYsv|-RurJw7Bna_gyhU_vQ@l68jZ&T5`VwS^-shOY>idtC&-s`!TZX`m&CW z=wvfby>u6kggDTdG4Hf)53!Dhok z$A1HEH9@fJV<_SvhAi|6l$$iRCtUELwpFi11-N$X6KlYi6+6xTYr( z_z{}r`;JRWH;J0_f8Nrk`sP3k^x-?`+9gkN5ZI(d?+2D2INfGUYfoWG_D8qitkyQA zj#exD0pTI$ljy-RVu;V2_WPyP%yWlQ$DXCrO6`(n|E;U}kI9i&?;h0hl2~FZ zVN>`i{1YHVu}F-DqHnx|X8ApYu3Vb&<=bEVB>v~KPv2~|etOWzJZfS)$Cy~j>VyP7 ze!lawb91k!#17Si?Whp!qE0KVTv{h>760B_{s#eVyZqDTiJNb@x4_oUe@=Q*7=*k6 z46DbXq7RuNI_4(8@r-oP|H-Dgq)v0@@i>cxcV+!;u0A+r&oLfv$jha1D1AhTn=$So zN0bwcO)T4t&KJ^p&v3%aX`xX`ij}VZ-6Z1WXEc|iE7o)^|NV*|kr5!}iMk(U+dTQ< zvN1|ajq6*MlbLPhQ1is1$x-0!}e0}n9DGkT&FmIWIx34--k;{G} ztpW#5fXRW0lgOJ4|If#3DC&3q^1M!-ErWhu%3>1bH!)G8)bV+YA6qucNLmv;({3WU z*Id`p>&s0fa)o8Wi5czZ|HQ)|J9$yy-k~0J$(!{n(aWU?i2GY1I#q0b7Be^ zoSV%T%|L>@((i7nZa!YmyHvc?Y}J}Pv7ji zXw1|s8yk&ZLX!w8;@VbvEBb=e$~&>aso)i+3hAW1dj3&x)@s6_s8IL0KR;w`ms;zp z2%^&<&-yz}7&(m%Ana{B3#|q>ZPvj4`G46aTu)u~JB--bCwb<}JY9Ne(ZivIL}GnZ z>+VmzSVo8sxMFF>uxdBWcmF@xk>7(~e)|YiOLKQbb~gUhsBs8OlqWu9R7VX+vq z5lex9o7do~*Y>A+*5D6K$Qexk-%56`;Y?bH_)7TC@k*|{5}}Gg5_k5?#{M6^&O559 ze0%$f1r-$)8&aa8fTAE>KoS+C3{_B(j?#tDJA{ZRNN>_hK)RGj3!R{#l+Zf_g7g|f zO9BZA@4>luoco*c{l~>}k;BP3-?sOD_UDPdbmkFj*frn<;WH5x3rO1V( z`(F<@6?c#mv{5wbH8XKYX@1`4mBYN2Sz=fi?e3iY(vf7!5ZXpl9`v_G=xpV_weII$ zAG{uh|L85m?xQsT>nld2>bUXh`E}uNU`)qbQ2fW4--sXiTgq}#w|<8lVLe=&o_dtS zwJl+&WzNOM15@@eH7im8)np zb>^G4@jkW{w%symZWimI7crtCL%-SHmtXi?=G05wGA~1OxL$gP^ZqOiXM9k3zX@a= zhS&9}H}0gym~#3|7$#j#mmfa%;|1Z$0@?2tms{kBArQ&h;r}K_YVn? z4utvtZJ-`$JhZ|ls;dgI21&r(K<@N8^P$ELE@Rdr7T1q|X;DACz5jj7h+}GgHeS-@ z=BCTALAqlZm-DiA;&Ha$UHGmKRO%BRBmdp&npTQPecj4r^9cjOzr#btp zQkZ!)ToC-c>24L!tC@VPRv$GuuO|c8S|{DutYRagTr*m{CewvNGU0BB(>uS+y?Ob4 zsD|-SgsJ0TkTAK~2R~G)WV74pv_Oq+G9mDRV!&FEn~A99@F^03bJ>tZsvHij7~Sgn zV8r^jk@bh{<+F_3bbu9J)CjjqF)z~JJ;o97gCon;qWko*EI$vg_AAs;XJ(+l z7e$KF*X$F2bZ_NoxnMFCwexWzM++|WVH^1HTc0EZnYBCBc%*pXMpS>sm%ASP#HFaI zc*$9YcS4b*oU5h)yUSKD`6}&ebkq=Jd3c@i*Ys65=wt#|@EO!BC`-5~hzmoMRs=Eh zozY+q>8~YiC64sXcH?O*oI{}GLP2y2hi>b{0V&K|ZH&n{Qks9f+WZZBm#2U`p@V6r zXNoeoRP@>Y*DUlnrNBlIp$6PSKH3q+3p>9m@-{)Q+fZlv`g_RvPL z15$5--XPWRK+k@1UvymKkD=t<%iHc|Y(g`xu0UPwd|qPgBWg zTUMI$xaDFKnl@@!h-t;I1w8rS-eiecx!YdT)2HuLSou?cZoKvXT!ubo~1n5ITxnKd5!`)Uj2|GM2Isa7t#ocb0otz zwqK4v{iRPN1;0LAE4o$qVEen+0zAvrQ&rBiCF8z-y-E zIwS7YOudA0(G^_LJL_ST=GTDaPX$sY*wDqA!r>9PAztj;-*$?)gF7IEMNOBgcB_~{ z4smw3KFi8>s$kY%u&_?>o1tTqZa~u@3i4t2T&Wf%fTNXk`@KBZ0yAoS@Y60f%IdaxyBa&@4H3y@D*Ak)X&W=TO|1>P zj*+mKFl>iuc@4KXY{5>;6zPs^FS-8)~zhk%pt0JvD;A-oGnMGcuOb*@o@O-oMGjQ$oi zTio#}#Fy|meq|iUg>KjtT}DD5&WS~J3354wvi95_n$2t?#;W2IFaeC4M`G3(ek};H zhaMh1tTJs;b1!K~QFlPIpE!vZrE_{`om_Jh@R_Mu&58D}d{pi#0J)Hp73@#@(e3>r zOLmhHZed)tQAESR?$0^bWksOOf92*ZN*N$Ewvju+FcT@@MBf+$$Ij^TOSBGH9+#sB?!pY3JZ z8~Vh&z{H&K@Rr~qdHyv%tA8oWA9)our$k_kuph-J2 zRPn<4t!lyK`=SbCAn&tcojtJDHe~`SEELC8! z2gcy$tE}tlFq2AX_W0@9khWic{j>Z*eu*^n&UD(1Ln`?e59bb-v@3-Y5F6~ke;d{= z8+I=AOi^b>At!!?JeL&i!-t?#+m>=>CLy3j=C8(Uav^+s#E-mk>c(I?_!6?<>5iB$ z{EZi%)3rB;3*)E4hrEA;^(iJBmJN>Q<%#xlnwYu97n8vX{n%n%o4KsYZP2fbMt#cZ zt*J7u>AeGa+W1cSlc!LDW>x369hux|j?}USM;kTruKw6AJf3EIW13Elr-e0F!Y}=G zm^va7{yKy$VKt5Ih32!_Z>ODYCVf>Bwg8zA@-Zk->ebFzU-o2FnwwYFj7@c0Z?)*l zSRfD2zj3uMtx@$_7ak|vN8Jx^FqI5mP&8l#snxs3xyw+VG_i=%iHg^)cRmDjX2);( zJ~15j5JsMiF2lt*$J=OO%nFy5(c_nOXPN(cVgHl{)UnE~;*iY6KeB4czK&1} z)KsfZb`)Qt1Th3FzY!d9@`aQ^j<0%{+SY;eYgBpb4Am{KQmQ|uva=JwdQSc3W`G`s zYtO9dvYq_w0?a&mPVPClGDk-#p{9Q7(d5y!CiSmZQ84iy9y|%Z<`HmZQS)f=Dp4_T zuT{jNsfVR6*sw~1xS*eO0sLr|rS)~Sc;V6@W&d1ZVxl?Pdsg!~q~dpt0+kG6HaXi# zBj1@dj~=>UTe<;=7mAxe!ucS{lLG?9TaLHFG{y(Bm0eSP@T;ST>ZUOIKs`Iw(caN3 zu&oJ{8?{0iI;c`WL2sw@FsuKI^m=dVD-^yCNn9dSGo6JDdYWz9D@-;$Iu9v)>NTXq zo4ItsbCD7=yjqG->^YET4fY41Y@MFQ*FQqu`iXt-Z1P^}oABTvV}F-#+Anb5cKyyD z5#~ExC`=zt`s!6pSmb1pyGKM=jxJbk!?$}+%09~Yz9Xs&G|Fg}u+iNcWTL)t3rpPc z{huN6*N|;F`#IofRA+Yy1~BNun!X}Tf8+O#Y^&YnavgYUOL{I zoAx9j;#<0`^yUHK1|kzUT)59){+9dTxR?n1cNv=&2JX(6U;T5XF3kioH_2~Kzfyw* zd`}eJZ!YOAqYt4fbHsKZlgxp9^eNu;`_^EVp@f3WD{yRZE4l7`VTAfoeuS|0VK2-w z|C*-%^G&X4*S~$I>Er46abYrOV(Z1~0f)&J)~TWwNWGN4>`t`|Km@vP$vo*zy{q5x zv&3QHz%7x_VQeFDS-T?w9QuWzQp-irsY_^Y9kXBC(BHdUeGW1Wxuq#i&)=A3g_Pp0 zH!Nzp`CY@_H$O29+Pbzz6{!np766W{Z}ycxw8(b8>>W?B@H>vkk?$rllYQc|c3+VT z@x)%z?-CY9`xBc5x7nq?-J6<1B||wwVn=3H{O95q^(WtZG(>-A26cYhWCj#&LJz;( z%CHuK-My9#dJFiiR~KeIU)tzvllUhX)OJv{NhkstoyE@ zIO~1($U)|>oqYlNhP07fC|aCv{$C1-f2L-Q_MbQ~z-^Fk-!M{&gz80-wqEVt>?P~n z<+}KxtbxLHCP&Tm_}Us(=>{>ZOCkB89zmdM!J`HO4$69aK z5iV)t(DCU5fm@W}4Ar|0*%#VlR9fZd9t<0DegNcZPbl&h8LC$(NSOSR-|xm*JcAe= zpR7~2=6FH;T3umh;}x{J;dbZ$ThUCu07g$3g zteNP2az;}z9P8^?CR3Sy(n$UQ?}*Jvjdluv1qTEaDAhS?4<_AYrDDm-FU*{oTToK&x~kzpEpDSH~7J8%Ekq&0mTy z#(aL2=$8UEs50OLiK`jF;YGK!%d}5&3@LU<6_Jw|6=0C?69=?-M+FE-dRC?AYUilF%)kMKD_VZ@LdgZ8vD$PjP+DrfvvEY`f5nmiJs@3*crAC7_)LqxFlVFq`OZB( z+e-tIb({u}8pLIv(^$xw=lX>a^P14vPA=2iaX04gXEn&RqGYAP27c-sfyM9)&#X`h zb%KS}IJ}+hD`ESD6xC$dLt@)+ZYJe|d24D4e!7^2u^EV-XBKsvnwfXSie4}m9wgO4 zsbT=6Jk!Zy`~ivMu6lx~6}N4jsDTZ7s&kzZSLC^Q{4haW!KQ{T$?Dw~;f^O~8PavQ zm6NQo&z?PN?u1iVDgm|0hEDkq+iktlX3j|f10teWW<&FEckjzvUmB--mowAeY;;5* zaBk8^lgDCA4*UuR{`^Vgf zaIuqDgLFps?%7(I5qf@SpCF=s%{#^AV5s-&1!pm~z`^Qbv(cazl&?sG692UULPr!3 zb&m`V!Y3|QP66>|swcMjiYj1(n}VRkTaOnhsY+L5C*8}>7Ih~?J)MoQ2%3(ZqO@=s z&$b3SKXq6uqD|*K(Dx-ei*yOIfX}I1<$#n{Cpo(bSoY^X9IzSThO=+`Bw5KFmL`2~ z5*p2Sq_2Y47Xm}p0g$aJCELmbU5mw>;~wqu$^0{9z$H-qj>K7h*TGpM>y^TN0T|uM~1`eKK5X83izDl~nK2?^@cN zk(IRUvG|&ySZp_Obpcmfo#eJt1aN#kJ()i5sa|fC=#S0Do2T#_<1X@Kr+9s24e3!% zfv;Vc=m_SH7lI}LJuy!XA~Gcb*n9<}or*fnaz<{YMYOL54V_K@X$>HAk zq6cYfSZ$qOX)tr{oWon~xu?Rdi<-hCpK4k0&hu&han~mHm0SHSTlSw(r~Z}U(qSk2 zZ_P(IG$RVFr~LSVHi;%IR@P_ux|$#(dzW)QxO5o^5{m0G!)_1J-| zBn%}cJzAQcmCtH%7q7jwmk%lj>v3m~uf7RRu4^2ydN>yc3jJWt-5v{M{$}#v7x@P1 z3n!?wQtu71O8hthqYZ&68l<4Qifg27GueqWb7g=dU26IGhHG#VfA-kc8~s5JHNj54 zRt)}q>>rL+!YXd_B9`lCw>J#wug-|@$@)^sxZT$^o9lci8+taP1+?pwtupc?ZXcQ- zy=%)nQU%D}Tiemw1uAm$Z_2-i#U|R&L#zQo`}a^!&6O&uf&19#F=ZZ=BMZD~PxA(w zXFs)*h_>FYc{PG7w@a+c?rm=h&pxv!kDvf{(dUiZx~SF>=cQ#Ul_M|_*FsnUmDYb7 z9rYMla}#Kx`Ou9Fi$;t&mE;=|3dr9RZCl64V*;J%)kq-1IIR)~bgFT4wq75OQ z7HncRr5nnF8BnZ?n4<7X``VY>e1Mg!7yFpo9o2BH@_b-k@6sw2=!6^0@6oHipps}v zr=0JW4I8Lk?ZJG{ZnZIA@3SN&%oDp5S0E2j3&?q0f$HxxCLf}pbdamQLm6Q*#%uzMBF}t-d0B|QoXWWW2`a<^Y&*=`{M5Jpbl9eb-ne9|G zb&rRpE2agM#3~{Rq01yyF)ldg4(_PNW1K9?di(~Ydh$-?Y~KTv*F-mLMmb8o=k$XD z-JvixSGPw}gVSv|PqGM?9k{q@Yko?tdBSY-TP(6lh!;Zs8novo(87c8dKn8NNbRZt zG%%Ye;lkbd_ZO3Gwuu6n&Uw#JHbtxt(#zfXgjW*oRxOzCS}n!gHnhPmg2)r&*=n}i zxbj`ZheX-lAc2rGV{=U#vn_j4IvhLXL8!FH+a!-x#V;N!-_R*;t%VzjhP1Dt7kjRC z3c#I%YSu@r93~FUVa+^3A=Cx6W#Lzw&m1L%a^tvbXGR!=t1Pvg%jVZ0+nexwEs*e; zKeDX{W#u(gl1V7N<*?0oi%17a4l}tv<%H?6VpWW72*N^MgEnanDNA=0iFX_$ijN#@ zx2($x{n~?Xk6TM~TIkU>YfmZ2YkepjC@-(X;a0zYebEYuef-2`v$Mw(W6k!r?Ad?9 zg!>Cj7H2<;tvR@UZycnZRw&!dD{wW2+NS68zn|yf^i92LN`Sr(8)W$-4d_8G#spIk zA5}KvCAoDYR<`s#wGe8U)m(29@uydG1kznP zBsi)22hG8et;`?f-o{zQG$No~+&H>o{r(=YO`&oE4mV?g$aC6PY%UEBqIz{b7N8X( zY3Z7L!l1jUXjlQ9Ld3K59b%FZ2xS!<-dH%4yFb)*lfl)k8h2Lid~6WN(jE_ z{Xt)=vs?=aQ@&~*SX-O2VTVmJKjUC(YU&~zs+%>_38uE;0t+4IRA*71C9(zQZ|U(4 z8aS45WR`UV15)(h$)4#^Fm?GhBgfsgP&%+IaPMxOxA|xE5q{jqX-!tTM0xF{>p=XX zRkiep=SMdW=`Tb^Ppaq%lcj0z7pknxKvy)`cTnmQiSW73bNE0U818I$8C|(}Bz~8S znMMpIv)|IKwa2_@3mY#+r|n?CcDn>9U3*A;_G zb{WIzYaG24JKF7H3-ne}^oZ|ww!X9!8_jS>Ef;|Vb)E`Ed7tFhsd;{wL=a%3VPQ`b zPjl&_tc!Lxhea4cPN`4C3QE((>4fh~?Fu1WCL>aWAwW~JK7?MbTr8*-VU4f^6v|3j zH>>qnj@!J#4zQieYzns;sd7$qS{Rk+$p?+KD$>0pg8Roaq&8O*r|`$`H>&UzOP?G$qDu(%J}CU> zG?|%(_!2x6zo~Ov$|$GQvUenSAf5}<7I*p{dVWtyE1+*5uRmwF>)pz|^=diz(EmLR zURIA};8r%t_L`bmISJWD@o*9pCuYdP=!Ti~RXIRka6`zTJNN=;=G=tbs735aLkNuP zEv67x=1O$2x#?T%&XxPHB7aG2v#;8bZK12Ma&%{_+F|jFCw6Yo;-%bfh==P7JGTSX zv8v>iDZx z8M>W`+hT@WJKG<*q(^U$js~L8-{c}ItG4uPw`b&F^Eseo;D~hI_F4L9K_aVV*=5n2 z@(AV)i)W)0~pwe9NSZPAcqutOG7F-*x3m2yR!6HQk&V62YV18b&QZk(;*P0Hs zJHL&g>z0@m>}<}VkHl>JN@)K#GWkQdo_2m9C^9QdV3D=TgXMK8&vNU+WW)riZ!d`c z5z;5A5BWdn>)90;K_*$ofc$hzc63yo=Xic**R%qBdta3U=YeRBbfOFi? zAZ{~$l+?!PG6qKz1A@1@6||?q_66GhJZC=>PB2GF6f%SLZ;uOhZgl64==qWg5{3tX zNu?Z9K;*n{dqHFs!ED|UsW@B7ClKcG)O*(-GLq4@njTtO-rr;1X(2SReZim@y1C7t zV6-&`Eyt#NFUIdS-$qxf%*IdG1E718%k)1$gu2On}&_qXLA{liu5=tQU(OjDBjaps zRm2-cHSq9uV!U*dXN(5KQCCu5jq0a#>;z{GqP8rtuzWZCOR)=HXS+MhHhfSntZ2}X zD!=1VK@L#ja7Rz=y+=i+HlT8m)XxgOLQL5QUJ(9t zq8n0bT)lL98PWhGcs!!6bTc25W-9mI@|7vSQ0U6)TJ9~=9yU}SbZ@)2cX|Z~JIN~^ z7|!o>nq+H`IO6&R`g(Nz1fb-=sIt7JQxM-K-MA|)za=?eP)`?Lm#FRpOhH-)k+eW}F;%8&+|ecwAF@VrRzKBo!&Xhq3P(DcenQ2ur!(0 z&W-E1H&vQHC>vI%Mlc{fvrHHY2v$D^bw$*Aj^O9#Kk0hI6QvjGU{r-{RSvvWt-%4t zx|Fo)y2btQ?*!!nx{B409&)|<bZ6fvS|5>5ob>DxXWbI?B z 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 hf&4^_lCM+i<>1 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 literal 0 HcmV?d00001 diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/assets/readmeImages/core-concepts.png b/app/multi-tenant/personal-space/cloud-cap-samples-java/assets/readmeImages/core-concepts.png new file mode 100644 index 0000000000000000000000000000000000000000..286989fc3f3ed9a9f9a1587e0f9d6b82f0a7d76e GIT binary patch literal 116291 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 literal 0 HcmV?d00001 diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/books.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/books.cds new file mode 100644 index 000000000..486e83282 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/books.cds @@ -0,0 +1,96 @@ +namespace my.bookshop; + +using { + Currency, + sap, + managed, + cuid +} from '@sap/cds/common'; +using my.bookshop.Reviews from './reviews'; +using my.bookshop.TechnicalBooleanFlag from './common'; + +@fiori.draft.enabled +entity Books : cuid, managed { + title : localized String(111); + descr : localized String(1111); + author : Association to Authors; + genre : Association to Genres; + stock : Integer; + price : Decimal(9, 2); + currency : Currency; + rating : Decimal(2, 1); + reviews : Association to many Reviews + on reviews.book = $self; + isReviewable : TechnicalBooleanFlag not null default true; + cHapters : Composition of many Chapters on cHapters.book = $self; + pages : Composition of many Pages on pages.book = $self; + virtual isAttachmentsUploadable : Boolean; + virtual isReferencesUploadable : Boolean; +} + +entity Authors : cuid, managed { + @assert.format : '^\p{Lu}.*' // assert that name starts with a capital letter + name : String(111); + dateOfBirth : Date; + dateOfDeath : Date; + placeOfBirth : String; + placeOfDeath : String; + books : Association to many Books + on books.author = $self; +} + +// annotations for Data Privacy +annotate Authors with +@PersonalData : { DataSubjectRole : 'Author', EntitySemantics : 'DataSubject' } +{ + ID @PersonalData.FieldSemantics : 'DataSubjectID'; + name @PersonalData.IsPotentiallySensitive; +} + +/** + * 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; +} + +/** Adding {Notebooks,Writers} for user service */ +entity Notebooks : managed, cuid { + @mandatory title : localized String(111); + descr : localized String(1111); + @mandatory writer : Association to Writers; + stock : Integer; + price : Decimal; + currency : Currency; + image : LargeBinary @Core.MediaType: 'image/png'; + virtual isAttachmentsUploadable : Boolean; +} + +entity Writers : managed, cuid { + @mandatory name : String(111); + dateOfBirth : Date; + dateOfDeath : Date; + placeOfBirth : String; + placeOfDeath : String; + notebooks : Association to many Notebooks + on notebooks.writer = $self; +} + +entity Chapters : cuid, managed { + book : Association to Books; + title : String @title: 'Chapter Title'; + description : String; + url : String; + chapterType : String @title: 'Chapter Type'; +} + +entity Pages : cuid, managed { + book : Association to Books; + title : String @title: 'Page Title'; + description : String; + url : String; + pageType : String @title: 'Page Type'; +} \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/common.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/common.cds new file mode 100644 index 000000000..a1c0cd805 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/common.cds @@ -0,0 +1,10 @@ +namespace my.bookshop; + +//////////////////////////////////////////////////////////////////////////// +// +// Commmon Types +// +type TechnicalBooleanFlag : Boolean @( + UI.Hidden, + Core.Computed +); diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/API_BUSINESS_PARTNER-A_BusinessPartnerAddress.csv b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/API_BUSINESS_PARTNER-A_BusinessPartnerAddress.csv new file mode 100644 index 000000000..0e0ab64c8 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/API_BUSINESS_PARTNER-A_BusinessPartnerAddress.csv @@ -0,0 +1,6 @@ +AddressID;BusinessPartner;Country;CityName;PostalCode;StreetName;HouseNumber +100;10401010;DE;Walldorf;68199;Dietmar-Hopp-Allee;16 +200;10401010;DE;St.Leon-Rot;68789;SAP-Allee;29 +300;10401010;DE;Potsdam;14469;Konrad-Zuse-Ring;10 +400;1000020;US;Newtown Square;19073;West Chester Pike;3999 +500;1000020;US;Palo Alto;94304;Hillview Avenue;3410 diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/Statuses.csv b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/Statuses.csv new file mode 100644 index 000000000..2cea5d749 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/Statuses.csv @@ -0,0 +1,6 @@ +code;text +Unscanned;Unscanned Attachment +Scanning;Scanning Attachment +Clean;Clean Attachment +Infected;Infected Attachment +Failed;Scanning Failed \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/Statuses_text.csv b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/Statuses_text.csv new file mode 100644 index 000000000..f205875c3 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/Statuses_text.csv @@ -0,0 +1,6 @@ +code;locale;text +Unscanned;en;Unscanned Attachment +Scanning;en;Scanning Attachment +Clean;en;Clean Attachment +Infected;en;Infected Attachment +Failed;en;Scanning Failed \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/WDIRICodeList.csv b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/WDIRICodeList.csv new file mode 100644 index 000000000..22ebc12db --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/WDIRICodeList.csv @@ -0,0 +1,4 @@ +code;name +1;1 +2;2 +3;3 \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/WDIRSCodeList.csv b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/WDIRSCodeList.csv new file mode 100644 index 000000000..d2bbc28bf --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/WDIRSCodeList.csv @@ -0,0 +1,4 @@ +code;name +A;Promotions type A +B;Promotions type B +C;Promotions type C \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Authors.csv b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Authors.csv new file mode 100644 index 000000000..84d7eb449 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Authors.csv @@ -0,0 +1,10 @@ +ID;NAME;DATEOFBIRTH;PLACEOFBIRTH;DATEOFDEATH;PLACEOFDEATH +335c7bcd-b826-4f14-a788-e0bf6738617a;Emily Brontë;1818-07-30;Thornton, Yorkshire;1848-12-19;Haworth, Yorkshire +e3da2c2e-72ee-45d5-8def-52964c7b252a;Charlote Brontë;1818-04-21;Thornton, Yorkshire;1855-03-31;Haworth, Yorkshire +e7643aae-2d2f-4656-bb2d-1328ad3c8045;Edgar Allen Poe;1809-01-19;Boston, Massachusetts;1849-10-07;Baltimore, Maryland +3c081d9d-abda-4da9-8b6a-4f4555bb26bc;Richard Carpenter;1929-08-14;King’s Lynn, Norfolk;2012-02-26;Hertfordshire, England +b834ddb0-613a-4edf-8d47-7d80989e1325;Jane Austen;1775-12-16;Steventon, United Kingdom;1817-07-18;Winchester, United Kingdom +a57f75fa-2bda-47b5-ab4d-b644570f29cd;F. Scott Fitzgerald;1896-09-24;Saint Paul, Minnesota;1940-12-21;Los Angeles, California +b22f5293-7eea-49bb-9ee7-17c5de81f1df;Harper Lee;1926-04-28;Monroeville, Alabama;2016-02-19;Monroeville, Alabama +1d2ec887-cbf1-491e-943e-33a2b4f39a6f;Gabriel García Márquez;1927-03-06;Aracataca, Columbia;2014-04-17;Mexico City, Mexico +c0526b1a-9a75-4a43-9133-163325cbbd2b;Truman Capote;1924-09-30;New Orleans, Louisiana;1984-08-25;Los Angeles, California diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Books.csv b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Books.csv new file mode 100644 index 000000000..dd4baa1a0 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Books.csv @@ -0,0 +1,6 @@ +ID;TITLE;DESCR;AUTHOR_ID;STOCK;PRICE;CURRENCY_CODE;GENRE_ID;RATING;ISBN +f846b0b9-01d4-4f6d-82a4-d79204f62278;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.";335c7bcd-b826-4f14-a788-e0bf6738617a;12;11.11;GBP;11;4.5;979-8698267973 +9b084139-0b1e-43b6-b12a-7b3669d75f02;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.";e3da2c2e-72ee-45d5-8def-52964c7b252a;11;12.34;GBP;11;3.0;979-8598716472 +51061ce3-ddde-4d70-a2dc-6314afbcc73e;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.";e7643aae-2d2f-4656-bb2d-1328ad3c8045;333;13.13;USD;16;2.5;978-1092909747 +aebdfc8a-0dfa-4468-bd36-48aabd65e663;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.";e7643aae-2d2f-4656-bb2d-1328ad3c8045;555;14;USD;16;1.0;979-8669820985 +4a519e61-3c3a-4bd9-ab12-d7e0c5329933;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.;3c081d9d-abda-4da9-8b6a-4f4555bb26bc;22;15;EUR;13;4.0;978-3473523023 diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Books.texts.csv b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Books.texts.csv new file mode 100644 index 000000000..b25a0a125 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Books.texts.csv @@ -0,0 +1,5 @@ +ID_TEXTS;ID;locale;title;descr +f846b0b9-01d4-4f6d-82a4-d79204f62278;f846b0b9-01d4-4f6d-82a4-d79204f62278;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. +f846b0b9-01d4-4f6d-82a4-d79204f62279;f846b0b9-01d4-4f6d-82a4-d79204f62278;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. +f846b0b9-01d4-4f6d-82a4-d79204f62280;9b084139-0b1e-43b6-b12a-7b3669d75f02;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 +f846b0b9-01d4-4f6d-82a4-d79204f62281;aebdfc8a-0dfa-4468-bd36-48aabd65e663;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. diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Genres.csv b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Genres.csv new file mode 100644 index 000000000..88e73bddb --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Genres.csv @@ -0,0 +1,16 @@ +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;21;Autobiography +23;20;Essay +24;20;Speech \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Notes.csv b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Notes.csv new file mode 100644 index 000000000..c5a069795 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Notes.csv @@ -0,0 +1,4 @@ +ID,note,address_businessPartner,address_ID +83e2643b-aecc-47d3-9f85-a8ba14eff07d,Packages can be dropped off at the reception,10401010,100 +880147b0-8d2d-4ef8-bb52-ae5ae6002fc5,Don't deliver packages after 5pm,10401010,100 +5efc842c-c70d-4ee2-af1d-81c7d257aff7,Ring at building 8,1000020,500 diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-OrderItems.csv b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-OrderItems.csv new file mode 100644 index 000000000..b13f3b2eb --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-OrderItems.csv @@ -0,0 +1,4 @@ +ID;QUANTITY;PARENT_ID;BOOK_ID;AMOUNT +58040e66-1dcd-4ffb-ab10-fdce32028b79;1;7e2f2640-6866-4dcf-8f4d-3027aa831cad;f846b0b9-01d4-4f6d-82a4-d79204f62278;11.11 +64e718c9-ff99-47f1-8ca3-950c850777d4;1;7e2f2640-6866-4dcf-8f4d-3027aa831cad;4a519e61-3c3a-4bd9-ab12-d7e0c5329933;15 +e9641166-e050-4261-bfee-d1e797e6cb7f;2;64e718c9-ff99-47f1-8ca3-950c850777d4;aebdfc8a-0dfa-4468-bd36-48aabd65e663;28 \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Orders.csv b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Orders.csv new file mode 100644 index 000000000..3439fcfb3 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Orders.csv @@ -0,0 +1,3 @@ +ID;CREATEDBY;ORDERNO;CURRENCY_CODE +7e2f2640-6866-4dcf-8f4d-3027aa831cad;john.doe@test.com;1;EUR +64e718c9-ff99-47f1-8ca3-950c850777d4;jane.doe@test.com;2;EUR diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Reviews.csv b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Reviews.csv new file mode 100644 index 000000000..679dcdd54 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/my.bookshop-Reviews.csv @@ -0,0 +1,25 @@ +MODIFIEDAT;CREATEDAT;BOOK_ID;RATING;TEXT;TITLE;CREATEDBY;ID +2019-11-26T03:29:46.178Z;2019-11-26T03:29:46.178Z;f846b0b9-01d4-4f6d-82a4-d79204f62278;1;So expensive. ...you can buy the same product for less money :( It broke after 1 day. Poor Quality. Called customer service..no answer. I'd expect a little more durability. I'm a dummy for not throwing all in the trash.;Just crazy! Don't buy it, PLEASE!;roman.zamora@test.sap.com;8089768a-14ae-3cd0-807e-c77ceab8f91e +2019-03-18T17:51:25.128Z;2019-03-18T17:51:25.128Z;f846b0b9-01d4-4f6d-82a4-d79204f62278;3;Lower quality than expected. Would buy a better quality next time. Works fine, but it is fragile.... For a straight up purchase not a bad choice. Does not look the same as the picture provided...which was disappointing, but ok. Packaging is not the same as getting it from the website. Everything's working like it should. Quite ok -- nothing extraordinary, though.;Exactly what I expected;minnie.biddle@test.sap.com;8098ea0a-e4b9-3265-9a21-95758a1e49e0 +2019-09-10T11:57:14.747Z;2019-09-10T11:57:14.747Z;f846b0b9-01d4-4f6d-82a4-d79204f62278;5;Can't relate to the bad reviews I saw, I definitely like it. This product is incredible awesome! Perfect for my needs. Wow, wow, wow. Speachless! This product has changed my life.;Highly recommended!;howard.pitts@test.sap.com;80a31701-4c04-3107-a50e-7a2ead69e421 +2018-09-20T06:33:01.940Z;2018-09-20T06:33:01.940Z;f846b0b9-01d4-4f6d-82a4-d79204f62278;5;Overall I am extremely pleased with it.;Great Product;frank.birdwell@test.sap.com;80b4a989-ca48-3b62-bc10-3545412152f8 +2019-11-15T19:56:56.923Z;2019-11-15T19:56:56.923Z;f846b0b9-01d4-4f6d-82a4-d79204f62278;1;Why is this even available here? We were able to return it for a full refund. I have to say that I'm quite disappointed. I'm a dummy for not throwing all in the trash. Too expensive for what I received. Not recommending to anyone. Very cheap. I don't recommend and will not purchase this brand again. I'm actually really surprised by the positive reviews, which I relied on when ordering.;Don't consider...;tyler.liu@test.sap.com;80d832ed-54c7-3296-bcb9-8a377af1639e +2019-03-06T12:37:07.494Z;2019-03-06T12:37:07.494Z;9b084139-0b1e-43b6-b12a-7b3669d75f02;1;Reading these reviews, I really had to wonder if I had bought the same product. Didn't work, that is why I cannot recommend this product. We were able to return it for a full refund. I'm a dummy for not throwing all in the trash. Not recommending to anyone. Very cheap. No instructions included for use or installation. The Worst I have ever seen!;Overrated and overpriced;latonya.nash@test.sap.com;80db5094-4fab-34cb-882a-84514eedd58f +2020-03-19T09:23:29.028Z;2020-03-19T09:23:29.028Z;9b084139-0b1e-43b6-b12a-7b3669d75f02;2;Works as advertised. Not good, not bad. Works fine, but it is fragile.... I would recommend this item to anyone who wants it. Not bad for the price I suppose. Does not look the same as the picture provided...which was disappointing, but ok. Material seems a bit cheaper than I had expected. It's okay. Nothing special to mention on this one.;Cheaply made, not so cheap price.;phillip.smart@test.sap.com;80db9105-b865-312e-acf8-ec42d9bff2cf +2019-05-04T13:59:10.057Z;2019-05-04T13:59:10.057Z;9b084139-0b1e-43b6-b12a-7b3669d75f02;5;Can't relate to the bad reviews I saw, I definitely like it. I do really love this product and think it's a good buy. I love it so much. It looks beautiful and modern. Never saw a quality like that before. Sleek product! A great purchase, thank you! I was surprised how nice this product really looks. Overall I am extremely pleased with it.;Perfect choice!;dona.lawrence@test.sap.com;814f6f8a-94a1-3f05-87f6-74c186536efe +2019-11-24T10:16:53.266Z;2019-11-24T10:16:53.266Z;9b084139-0b1e-43b6-b12a-7b3669d75f02;5;Excellent engineering and the feeling of a very high quality product. I love it so much. I do really love this product and think it's a good buy. Unique and beautiful. Excellent quality. Great service. I would buy this product again, if I ever need too, big smile. Not expensive for the quality. Why didn't I buy these sooner? Such a cool Design! That was a good choice, would definitely pick it again.;Nice Product!;dustin.park@test.sap.com;81718a76-0ecd-3aa1-97b8-c04df011aa16 +2019-06-13T18:24:50.994Z;2019-06-13T18:24:50.994Z;9b084139-0b1e-43b6-b12a-7b3669d75f02;1;Too expensive for what I received. Not recommending to anyone. Very cheap. This is a role model for annoying a customer.;Not Suggested;phillip.brewer@test.sap.com;8186e063-0e1c-3310-9313-451bcef5f1f6 +2018-08-11T10:49:14.710Z;2018-08-11T10:49:14.710Z;51061ce3-ddde-4d70-a2dc-6314afbcc73e;5;Fantastic, I'm totally blown away. After using that product my business skyrocketed! Why didn't I buy these sooner? Such a cool Design! Everyone in my big family has one now - both adults, four teen and one middle schooler. It's convienent for me.;Love this brand!;rita.spencer@test.sap.com;819b6821-3482-3fd5-963b-ea9361d60986 +2020-11-07T07:45:10.731Z;2020-11-07T07:45:10.731Z;51061ce3-ddde-4d70-a2dc-6314afbcc73e;2;Haven't seen good alternatives, so I picked this one. Would buy a better quality next time. It does it's job. For a straight up purchase not a bad choice. I would recommend this item to anyone who wants it. Quite ok -- nothing extraordinary, though.;Well...;kelly.zheng@test.sap.com;819da75a-2d12-3167-86bf-8987f82d7c12 +2020-01-12T22:01:00.127Z;2020-01-12T22:01:00.127Z;51061ce3-ddde-4d70-a2dc-6314afbcc73e;1;It is fatally flawed and should be avoided. Nice looking product, but never worked well. I'm a dummy for not throwing all in the trash.;It's just ok;jay.townsend@test.sap.com;81aaf7f7-e6cf-3650-9b9f-660588e2ca38 +2020-06-20T05:07:17.150Z;2020-06-20T05:07:17.150Z;51061ce3-ddde-4d70-a2dc-6314afbcc73e;5;Does what it should, so definitely deserves a good rating. Definitely worth the investment. Unique and beautiful. Excellent quality. Great service. A great purchase, thank you! They hold up and last a very long time. Great quality and exactly what was described. I looked around quite a bit before deciding to try this and it fulfills all that I wanted. That was a good choice, would definitely pick it again.;Great Product;lawrence.harp@test.sap.com;81d030d3-90ba-3bd1-bef8-0347d990bcdf +2018-09-25T13:54:52.786Z;2018-09-25T13:54:52.786Z;51061ce3-ddde-4d70-a2dc-6314afbcc73e;1;I should have read the reviews that warned about how short, or small, this product is. I'd expect a little more durability. Lower quality than expected. I don't recommend and will not purchase this brand again. I'm actually really surprised by the positive reviews, which I relied on when ordering. Didn't receive what the picture looked like. This is a role model for annoying a customer.;Don't buy;eddie.hart@test.sap.com;81d1152c-acbb-3fa1-abbc-66397150f2eb +2018-09-19T17:30:31.927Z;2018-09-19T17:30:31.927Z;aebdfc8a-0dfa-4468-bd36-48aabd65e663;2;Go for it, not really bad at all. Works as advertised. I would recommend this item to anyone who wants it. It serves the intended purpose.;Ok, but has a few issues;stephen.bratten@test.sap.com;81ea3917-8374-38b2-897d-000ced6c10db +2020-09-07T16:28:48.032Z;2020-09-07T16:28:48.032Z;aebdfc8a-0dfa-4468-bd36-48aabd65e663;1;Called customer service..no answer. Horrible! Unsatisfied in every way! No instructions included for use or installation.;Please don't;karrie.lawrence@test.sap.com;81f015f4-59c2-33ef-8d2e-d77692e7ce8e +2018-05-21T22:58:40.021Z;2018-05-21T22:58:40.021Z;aebdfc8a-0dfa-4468-bd36-48aabd65e663;1;So expensive. ...you can buy the same product for less money :( The description is wrong. I sent it back. Looks better than it works. Horrible! Unsatisfied in every way! Lower quality than expected. This is a role model for annoying a customer.;Useless;abbie.banes@test.sap.com;81fa4a9e-4071-3c74-a07e-8bae2ca88168 +2018-12-01T14:29:03.340Z;2018-12-01T14:29:03.340Z;aebdfc8a-0dfa-4468-bd36-48aabd65e663;5;I love it so much. Unique and beautiful. Excellent quality. Great service. I was surprised how nice this product really looks.;You need this!;marshall.alexander@test.sap.com;82011880-e1aa-3019-8899-dee0647d2be8 +2020-03-07T06:46:29.181Z;2020-03-07T06:46:29.181Z;aebdfc8a-0dfa-4468-bd36-48aabd65e663;1;Didn't work, that is why I cannot recommend this product. I'd expect a little more durability.;I don't recommend and will not purchase this brand again;kay.steinberg@test.sap.com;8216ead4-3292-38e6-a53f-ecf0555bc9f2 +2018-08-22T00:11:59.829Z;2018-08-22T00:11:59.829Z;4a519e61-3c3a-4bd9-ab12-d7e0c5329933;5;Definitely worth the investment. Does what it should, so definitely deserves a good rating. The good things are still available, this is the proof! This is great! Unique and beautiful. Excellent quality. Great service. They hold up and last a very long time. It's convienent for me. That was a good choice, would definitely pick it again.;Good value;isabelle.wong@test.sap.com;823e509b-8565-3a12-8cbb-2af042e5e509 +2018-08-19T16:11:20.884Z;2018-08-19T16:11:20.884Z;4a519e61-3c3a-4bd9-ab12-d7e0c5329933;1;Nice looking product, but never worked well. I'd expect a little more durability. Lower quality than expected.;Don't buy;tracy.zhang@test.sap.com;827ebe9b-b6d0-36ea-a3dc-3ca50bc4809b +2020-06-28T10:00:33.344Z;2020-06-28T10:00:33.344Z;4a519e61-3c3a-4bd9-ab12-d7e0c5329933;2;I didn't bother to return it but will not be purchasing this again. If you're looking for something durable and heavy-duty I would not recommend this one. It does it's job. Works as advertised. Works fine, but it is fragile.... Does not look the same as the picture provided...which was disappointing, but ok. Quite ok -- nothing extraordinary, though.;Just regular general purpose;rodney.franklin@test.sap.com;82813174-e1f2-31f5-8b8c-1d044857979d +2020-11-07T03:11:14.727Z;2020-11-07T03:11:14.727Z;4a519e61-3c3a-4bd9-ab12-d7e0c5329933;5;Does what it should, so definitely deserves a good rating. Fantastic, I'm totally blown away. This is great! They hold up and last a very long time. Not expensive for the quality. Why didn't I buy these sooner? Such a cool Design! This product is incredible awesome! It's convienent for me. Wow, wow, wow. Speachless!;Good Value - Good Quality;phillip.smart@test.sap.com;8298deea-443c-372e-bba3-628b003f6845 \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/sap.attachments-UploadScanStates.csv b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/sap.attachments-UploadScanStates.csv new file mode 100644 index 000000000..8432b60db --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/sap.attachments-UploadScanStates.csv @@ -0,0 +1,6 @@ +code;name;criticality +uploading;Uploading;5 +Success;Success;3 +Failed;Scan failed;2 +VirusDetected;Virus Detected;1 +VirusScanInprogress;Virus Scan In Progress(refresh page);5 \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/sap.common-Currencies.csv b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/sap.common-Currencies.csv new file mode 100644 index 000000000..d68d1028a --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/sap.common-Currencies.csv @@ -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 Britian Pound +ILS;₪;Shekel;Israeli New Shekel \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/sap.common-Currencies.texts.csv b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/sap.common-Currencies.texts.csv new file mode 100644 index 000000000..b192b4c1a --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/sap.common-Currencies.texts.csv @@ -0,0 +1,13 @@ +CODE;LOCALE;NAME;DESCR +EUR;de;Euro;European Euro +USD;de;US-Dollar;United States Dollar +CAD;de;Kanadischer Dollar;Kanadischer Dollar +AUD;de;Australischer Dollar;Australischer Dollar +GBP;de;Pfund;Britische Pfund +ILS;de;Schekel;Israelische Schekel +EUR;fr;euro;de la Zone euro +USD;fr;dollar;dollar des États-Unis +CAD;fr;dollar canadien;dollar canadien +AUD;fr;dollar australien;dollar australien +GBP;fr;livre sterling;pound sterling +ILS;fr;Shekel;shekel israelien \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/sap.common-Languages.csv b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/sap.common-Languages.csv new file mode 100644 index 000000000..c935d462f --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/sap.common-Languages.csv @@ -0,0 +1,7 @@ +name;descr;code +Spanish;Spanish;es +English;English;en +French;French;fr +German;German;de +Italian;Italian;it +Russian;Russian;ru diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/sap.common-Languages.texts.csv b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/sap.common-Languages.texts.csv new file mode 100644 index 000000000..5949b2f6a --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/data/sap.common-Languages.texts.csv @@ -0,0 +1,19 @@ +name;descr;code;locale +Spanish;Spanish;es;en +English;English;en;en +French;French;fr;en +German;German;de;en +Italian;Italian;it;en +Russian;Russian;ru;en +espagnol;espagnol;es;fr +anglais;anglais;en;fr +français;français;fr;fr +allemand;allemand;de;fr +italien;italien;it;fr +russe;russe;ru;fr +Spanisch;Spanisch;es;de +Englisch;Englisch;en;de +Französisch;Französisch;fr;de +Deutsch;Deutsch;de;de +Italienisch;Italienisch;it;de +Russisch;Russisch;ru;de diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/index.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/index.cds new file mode 100644 index 000000000..8d94253a2 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/index.cds @@ -0,0 +1,6 @@ +using from './books'; +using from './orders'; +using from './reviews'; +using from './notes'; +using from './common'; +using from '@sap/cds/srv/outbox'; diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/notes.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/notes.cds new file mode 100644 index 000000000..47d3687ca --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/notes.cds @@ -0,0 +1,7 @@ +namespace my.bookshop; + +using { cuid } from '@sap/cds/common'; + +entity Notes: cuid { + note: String; +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/orders.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/orders.cds new file mode 100644 index 000000000..e09ef50b8 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/orders.cds @@ -0,0 +1,25 @@ +namespace my.bookshop; + +using { + Currency, + User, + managed, + cuid +} from '@sap/cds/common'; +using my.bookshop.Books from './books'; + +entity Orders : cuid, managed { + OrderNo : String @title : '{i18n>OrderNumber}' @mandatory; //> readable key + Items : Composition of many OrderItems + on Items.parent = $self; + buyer : User; + total : Decimal(9, 2)@readonly; + currency : Currency; +} + +entity OrderItems : cuid { + parent : Association to Orders; + book : Association to Books @mandatory @assert.target; + quantity : Integer; + amount : Decimal(9, 2); +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/package-lock.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/package-lock.json new file mode 100644 index 000000000..6477c690e --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/package-lock.json @@ -0,0 +1,179 @@ +{ + "name": "deploy", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "deploy", + "dependencies": { + "@sap/hdi-deploy": "4.8.2" + }, + "engines": { + "node": "^18" + } + }, + "node_modules/@sap/hdi-deploy": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/@sap/hdi-deploy/-/hdi-deploy-4.8.2.tgz", + "integrity": "sha512-LDouJ0i6oTLOrYWLeyp4PKF5cIBeKnn70gksdlg/bq3q5G/UNgGmqL62TEHbXehbeJfc0DKfEp9yal4IFD5k1Q==", + "hasShrinkwrap": true, + "dependencies": { + "@sap/hana-client": "2.18.24", + "@sap/hdi": "4.5.1", + "@sap/xsenv": "3.4.0", + "async": "3.2.3", + "dotenv": "10.0.0", + "handlebars": "4.7.7", + "hdb": "0.19.3", + "micromatch": "4.0.4" + }, + "engines": { + "node": "^12.0.0 || ^14.0.0 || ^16.0.0 || ^18.0.0 || ^20.0.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/hana-client": { + "version": "2.18.24", + "dependencies": { + "debug": "3.1.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/hana-client/node_modules/debug": { + "version": "3.1.0", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/hana-client/node_modules/ms": { + "version": "2.0.0" + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/hdi": { + "version": "4.5.1", + "dependencies": { + "async": "3.2.3" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv": { + "version": "3.4.0", + "dependencies": { + "debug": "4.3.3", + "node-cache": "^5.1.0", + "verror": "1.10.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/assert-plus": { + "version": "1.0.0" + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/clone": { + "version": "2.1.2" + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/core-util-is": { + "version": "1.0.2" + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/debug": { + "version": "4.3.3", + "dependencies": { + "ms": "2.1.2" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/extsprintf": { + "version": "1.4.1" + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/ms": { + "version": "2.1.2" + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/node-cache": { + "version": "5.1.2", + "dependencies": { + "clone": "2.x" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/verror": { + "version": "1.10.0", + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/async": { + "version": "3.2.3" + }, + "node_modules/@sap/hdi-deploy/node_modules/braces": { + "version": "3.0.2", + "dependencies": { + "fill-range": "^7.0.1" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/dotenv": { + "version": "10.0.0" + }, + "node_modules/@sap/hdi-deploy/node_modules/fill-range": { + "version": "7.0.1", + "dependencies": { + "to-regex-range": "^5.0.1" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/handlebars": { + "version": "4.7.7", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/hdb": { + "version": "0.19.3", + "dependencies": { + "iconv-lite": "^0.4.18" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/iconv-lite": { + "version": "0.4.24", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/is-number": { + "version": "7.0.0" + }, + "node_modules/@sap/hdi-deploy/node_modules/micromatch": { + "version": "4.0.4", + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/minimist": { + "version": "1.2.8" + }, + "node_modules/@sap/hdi-deploy/node_modules/neo-async": { + "version": "2.6.2" + }, + "node_modules/@sap/hdi-deploy/node_modules/picomatch": { + "version": "2.3.1" + }, + "node_modules/@sap/hdi-deploy/node_modules/safer-buffer": { + "version": "2.1.2" + }, + "node_modules/@sap/hdi-deploy/node_modules/source-map": { + "version": "0.6.1" + }, + "node_modules/@sap/hdi-deploy/node_modules/to-regex-range": { + "version": "5.0.1", + "dependencies": { + "is-number": "^7.0.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/uglify-js": { + "version": "3.17.4", + "optional": true + }, + "node_modules/@sap/hdi-deploy/node_modules/wordwrap": { + "version": "1.0.0" + } + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/package.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/package.json new file mode 100644 index 000000000..491f70822 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/package.json @@ -0,0 +1,13 @@ +{ + "name": "deploy", + "dependencies": { + "@sap/hdi-deploy": "4.8.2" + }, + "engines": { + "node": "^18" + }, + "scripts": { + "start": "node node_modules/@sap/hdi-deploy/deploy.js", + "build": "npm i && npx cds build .. --for hana --production" + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/pom.xml b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/pom.xml new file mode 100644 index 000000000..73a205b88 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + + bookshop-parent + my + ${revision} + + + db + + + + + com.sap.cds + sdm + 1.0.0-RC1 + + + + + + + com.sap.cds + cds-maven-plugin + ${cds.services.version} + + + cds.clean + + clean + + + + cds.resolve + + resolve + + + + + + + + diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/repository.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/repository.cds new file mode 100644 index 000000000..ae103dc8d --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/repository.cds @@ -0,0 +1,11 @@ +namespace my.bookshop; + +using { + cuid +} from '@sap/cds/common'; + +entity Repository : cuid { + repositoryId : localized String(111); + externalId : localized String(1111); + name : localized String(1111); +} \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/db/reviews.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/reviews.cds new file mode 100644 index 000000000..7015fbf62 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/db/reviews.cds @@ -0,0 +1,31 @@ +namespace my.bookshop; + +using { + User, + managed, + cuid +} from '@sap/cds/common'; +using my.bookshop.Books from './books'; + +entity Reviews : cuid, managed { + @cds.odata.ValueList + book : Association to Books; + rating : Rating; + title : String(111); + text : String(1111); +} + +// input validation +annotate Reviews with { + title @mandatory; + rating @assert.range; + book @mandatory @assert.target; +} + +type Rating : Integer enum { + Best = 5; + Good = 4; + Avg = 3; + Poor = 2; + Worst = 1; +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/fts/isbn/schema.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/fts/isbn/schema.cds new file mode 100644 index 000000000..c26572691 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/fts/isbn/schema.cds @@ -0,0 +1,31 @@ +using {CatalogService} from '../../app/browse/fiori-service'; +using {my.bookshop as my} from '../../db/index'; + + +// domain model + +extend my.Books with { + isbn : String(40) @cds.collate: false; +} + +// Feature 'isbn' will display ISBN in table and on object page +annotate CatalogService.Books with @(UI: { + FieldGroup #General: {Data: [ + ...up to + {Value: title}, + { + Value: isbn, + Label: '{i18n>ISBN}' + }, + ... + ]}, + LineItem: [ + ...up to + {Value: title}, + { + Value: isbn, + Label: '{i18n>ISBN}' + }, + ... + ] +}); diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/integration-tests/pom.xml b/app/multi-tenant/personal-space/cloud-cap-samples-java/integration-tests/pom.xml new file mode 100644 index 000000000..0d3f7bc73 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/integration-tests/pom.xml @@ -0,0 +1,135 @@ + + 4.0.0 + + + my + bookshop-parent + ${revision} + + + bookshop-integration-tests + + bookshop-integration-tests + + + ../mtx/sidecar + node + + + + + my + bookshop + ${revision} + + + ch.qos.logback + logback-classic + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.security + spring-security-test + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.5 + + false + + + + + org.graalvm.buildtools + native-maven-plugin + + true + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + 3.2.5 + + + + integration-test + verify + + + + + + + com.sap.cds + cds-maven-plugin + ${cds.services.version} + + + cds.install-node + + install-node + + + ${cdsdk-global} + + + + + install-sidecar + + npm + + pre-integration-test + + install --no-save + ${skipTests} + ${sidecar.dir} + + + + + + + org.codehaus.mojo + exec-maven-plugin + 3.2.0 + + + pre-integration-test + start-sidecar + + exec + + + + + ${cds.node.executable} + ${skipTests} + ${sidecar.dir} + true + true + node_modules/@sap/cds/bin/cds-serve.js + + + + + diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/integration-tests/src/test/java/my/bookshop/it/FeatureTogglesIT.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/integration-tests/src/test/java/my/bookshop/it/FeatureTogglesIT.java new file mode 100644 index 000000000..816337c4b --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/integration-tests/src/test/java/my/bookshop/it/FeatureTogglesIT.java @@ -0,0 +1,58 @@ +package my.bookshop.it; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; + +// This test case is executable only when MTX sidecar is running. +@ActiveProfiles({"default", "ft"}) +@AutoConfigureMockMvc +@SpringBootTest +class FeatureTogglesIT { + + private static final String ENDPOINT = "/api/browse/Books(aebdfc8a-0dfa-4468-bd36-48aabd65e663)"; + + @Autowired + private MockMvc client; + + @Test + @WithMockUser("authenticated") // This user has all feature toggles disabled + void withoutToggles_basicModelVisible() throws Exception { + // Elements are not visible and not changed by the event handler + client.perform(get(ENDPOINT)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.isbn").doesNotExist()) + .andExpect(jsonPath("$.title").value(containsString("11%"))); + } + + @Test + @WithMockUser("admin") // This user has all feature toggles enabled + void togglesOn_extensionsAndChangesAreVisible() throws Exception { + // Elements are visible and changed by the event handler + client.perform(get(ENDPOINT)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.isbn").value("979-8669820985")) + .andExpect(jsonPath("$.title").value(containsString("14%"))); + } + + @Test + @WithMockUser("user") // This user has only 'isbn' toggle enabled + void toggleIsbnOn_extensionsAndChangesAreVisible() throws Exception { + // Elements are visible + client.perform(get(ENDPOINT)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.isbn").value("979-8669820985")) + .andExpect(jsonPath("$.title").value(containsString("11%"))); + } + +} + diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/mta-single-tenant.yaml b/app/multi-tenant/personal-space/cloud-cap-samples-java/mta-single-tenant.yaml new file mode 100644 index 000000000..2ee6770a1 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/mta-single-tenant.yaml @@ -0,0 +1,95 @@ +_schema-version: '2.1' +ID: bookshop +version: 1.0.0 +description: "Bookshop CAP Java Project with UI" +parameters: + enable-parallel-deployments: true +modules: +# --------------------- SERVER MODULE ------------------------ + - name: bookshop-srv +# ------------------------------------------------------------ + type: java + path: srv + parameters: + memory: 1024M + disk-quota: 512M + buildpack: sap_java_buildpack_jakarta + properties: + SPRING_PROFILES_ACTIVE: cloud,sandbox + JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jre.SAPMachineJRE']" + JBP_CONFIG_SAP_MACHINE_JRE: '{ version: 21.+ }' + build-parameters: + builder: custom + commands: + - mvn clean package -DskipTests=true + build-result: target/*-exec.jar + requires: + - name: bookshop-hdi-container + - name: bookshop-uaa-rashminew + - name: cf-logging + provides: + - name: srv-api + properties: + srv-url: '${default-url}' +# --------------------- DB MODULE --------------------------- + - name: bookshop-db +# ----------------------------------------------------------- + type: hdb + path: db + parameters: + buildpack: nodejs_buildpack + build-parameters: + builder: custom + commands: + - npm run build + requires: + - name: bookshop-srv + requires: + - name: bookshop-hdi-container +# --------------------- APPROUTER MODULE --------------------- + - name: bookshop-app +# ------------------------------------------------------------ + type: approuter.nodejs + path: app + parameters: + memory: 256M + disk-quota: 512M + requires: + - name: srv-api + group: destinations + properties: + name: backend + url: ~{srv-url} + forwardAuthToken: true + strictSSL: true + - name: bookshop-uaa-rashminew + provides: + - name: app-api + properties: + app-url: '${default-url}' +# --------------------- RESOURCES --------------------- +resources: +# ----------------------------------------------------- + - name: bookshop-uaa-rashminew + type: org.cloudfoundry.managed-service + parameters: + service: xsuaa + service-plan: application + path: ./xs-security.json + config: # override xsappname as it needs to be unique + xsappname: bookshopnew-${org}-${space} + oauth2-configuration: + redirect-uris: + - ~{app-api/app-url}/** + requires: + - name: app-api + - name: bookshop-hdi-container + type: org.cloudfoundry.managed-service + parameters: + service: hana + service-plan: hdi-shared + - name: cf-logging + type: org.cloudfoundry.managed-service + parameters: + service: application-logs + service-plan: lite diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/mtx/sidecar/package.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/mtx/sidecar/package.json new file mode 100644 index 000000000..451cb8a6f --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/mtx/sidecar/package.json @@ -0,0 +1,25 @@ +{ + "dependencies": { + "@cap-js/hana": "^2.1.1", + "@sap/cds": ">=9.8.0", + "@sap/cds-mtxs": "^3", + "@sap/xssec": "^4.2.7", + "express": "^4" + }, + "devDependencies": { + "sqlite3": "^5" + }, + "engines": { + "node": "^20" + }, + "cds": { + "profiles": ["mtx-sidecar", "java"], + "[development]": { + "requires": { "auth": "dummy" } + } + }, + "scripts": { + "start": "cds-serve", + "build": "cds build ../.. --for mtx-sidecar --production && cd gen && npm install" + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/package.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/package.json new file mode 100644 index 000000000..001ac052b --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/package.json @@ -0,0 +1,13 @@ +{ + "name": "bookshop-java", + "version": "1.0.0", + "description": "Bookshop using CAP Java NG", + "license": "Apache License Version 2.0", + "repository": "https://github.com/SAP-samples/cloud-cap-samples-java.git", + "dependencies": { + "@cap-js/hana": "^2.1.2", + "@sap/cds": "^9.2.0", + "@sap/cds-dk": "^9.3.1", + "@sap/cds-mtxs": "^3" + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/pom.xml b/app/multi-tenant/personal-space/cloud-cap-samples-java/pom.xml new file mode 100644 index 000000000..c2c6df6ae --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/pom.xml @@ -0,0 +1,171 @@ + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.2.6 + + + + my + bookshop-parent + ${revision} + pom + + bookshop parent + + + + 1.0.0-SNAPSHOT + + + 21 + 4.3.0 + 5.12.0 + 3.5.0 + 3.8.3 + 9.3.1 + + + + srv + integration-tests + + + + + + + com.sap.cds + cds-services-bom + ${cds.services.version} + pom + import + + + + + + com.sap.cloud.sdk + sdk-modules-bom + ${cloud.sdk.version} + pom + import + + + + + com.sap.cloud.security + java-bom + ${xsuaa.version} + pom + import + + + + + com.sap.cloud.servicesdk.xbem + emjapi-extension-sap-cp-jms + 4.0.0 + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.12.1 + + ${jdk.version} + UTF-8 + + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.5 + + true + + + + + org.apache.maven.plugins + maven-failsafe-plugin + 3.2.5 + + + + + org.codehaus.mojo + flatten-maven-plugin + 1.6.0 + + true + resolveCiFriendliesOnly + + + + flatten + process-resources + + flatten + + + + flatten.clean + clean + + clean + + + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.4.1 + + + Project Structure Checks + + enforce + + + + + 3.5 + + + ${jdk.version} + + + + true + + + + + + + diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/requests.http b/app/multi-tenant/personal-space/cloud-cap-samples-java/requests.http new file mode 100644 index 000000000..c8c0e0192 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/requests.http @@ -0,0 +1,16 @@ +### Trigger BusinessPartner.Changed event through S/4 mock + +PATCH http://localhost:8080/api/API_BUSINESS_PARTNER/A_BusinessPartnerAddress(BusinessPartner='10401010',AddressID='200') +Content-Type: application/json +Authorization: Basic authenticated: + +{"HouseNumber": "30"} + +### Subscribe t1 tenant, in local-mtxs + +POST http://localhost:4005/-/cds/deployment/subscribe HTTP/1.1 +Content-Type: application/json + +{ + "tenant": "t1" +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/scripts/create-container-registry-secret.sh b/app/multi-tenant/personal-space/cloud-cap-samples-java/scripts/create-container-registry-secret.sh new file mode 100755 index 000000000..e18abeafb --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/scripts/create-container-registry-secret.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +read -p "Docker Server: " DOCKER_SERVER + +read -p "User ($USER): " DOCKER_USER +if [ "$DOCKER_USER" == "" ]; then + DOCKER_USER="$USER" +fi + +if [ "$EMAIL" == "" ]; then + read -p "EMail: " DOCKER_EMAIL +else + read -p "EMail ($EMAIL): " DOCKER_EMAIL + if [ "$DOCKER_EMAIL" == "" ]; then + DOCKER_EMAIL="$EMAIL" + fi +fi + +read -sp "API Key: " API_KEY + +echo +echo + +kubectl create secret docker-registry container-registry \ + "--docker-server=$DOCKER_SERVER" \ + "--docker-username=$DOCKER_USER" \ + "--docker-email=$DOCKER_EMAIL" \ + "--docker-password=$API_KEY" diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/scripts/create-db-secret.sh b/app/multi-tenant/personal-space/cloud-cap-samples-java/scripts/create-db-secret.sh new file mode 100755 index 000000000..9282a2098 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/scripts/create-db-secret.sh @@ -0,0 +1,78 @@ +#!/bin/bash + +set -e +cd "$(dirname "$(dirname "$0")")" + +npm install --no-save yaml + +function value() { + node ./scripts/value.js "$1" +} + +NAME="$1" +if [ "$NAME" == "" ]; then + NAME="$(value srv.bindings.db.fromSecret)" + if [ "$NAME" == "" -o "$NAME" == "" ]; then + echo >&2 "[ERROR] Please either specify the name for the DB secret or maintain it in the Helm chart" + exit 1 + fi +fi + +SECRET_HEADER="$(cat </dev/null >/dev/null service $NAME || cf create-service hana hdi-shared $NAME +while true; do + STATUS="$(cf 2>/dev/null service $NAME | grep status: | head -n 1)" + echo $STATUS + if [[ "$STATUS" = *succeeded* ]]; then + break + fi + sleep 1 +done + +cf create-service-key $NAME $NAME-key + +node "$(dirname "$0")/format-kyma-secret.js" -- "$(echo "$SECRET_HEADER")" "$(cf service-key $NAME $NAME-key)" | kubectl apply -f - +echo +echo "HANA DB Kubernetes secret '$NAME' created." +echo +echo "You can view it using:" +echo +echo "kubectl get secret $NAME -o yaml" +exit 0 \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/scripts/create-sm-secret.sh b/app/multi-tenant/personal-space/cloud-cap-samples-java/scripts/create-sm-secret.sh new file mode 100755 index 000000000..aecc9ada3 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/scripts/create-sm-secret.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +set -e +cd "$(dirname "$(dirname "$0")")" + +npm install --no-save yaml + +function value() { + node ./scripts/value.js "$1" +} + +NAME="$1" +if [ "$NAME" == "" ]; then + if [ ! -f "chart/values.yaml" ]; then + echo >&2 "[ERROR] Please either specify the name for the service manager secret or maintain it in the Helm chart" + exit 1 + fi + NAME="$(value .srv.bindings.db.fromSecret)" + if [ "$NAME" == "" -o "$NAME" == "" ]; then + echo >&2 "[ERROR] Please either specify the name for the service manager secret or maintain it in the Helm chart" + exit 1 + fi +fi + +SECRET_HEADER="$(cat </dev/null >/dev/null service $NAME || cf create-service service-manager container $NAME +while true; do + STATUS="$(cf 2>/dev/null service $NAME | grep status: | head -n 1)" + echo $STATUS + if [[ "$STATUS" = *succeeded* ]]; then + break + fi + sleep 1 +done + +cf create-service-key $NAME $NAME-key + +node "$(dirname "$0")/format-kyma-secret.js" -- "$(echo "$SECRET_HEADER")" "$(cf service-key $NAME $NAME-key)" | kubectl apply -f - +echo +echo "Service Manager container secret '$NAME' created." +echo +echo "You can view it using:" +echo +echo "kubectl get secret $NAME -o yaml" +exit 0 \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/scripts/format-kyma-secret.js b/app/multi-tenant/personal-space/cloud-cap-samples-java/scripts/format-kyma-secret.js new file mode 100644 index 000000000..eccc78a6b --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/scripts/format-kyma-secret.js @@ -0,0 +1,9 @@ +const key=JSON.parse(process.argv[4].replace(/^.*/, "")); +const credentials=key.credentials /* new cfcli? */ || key; +console.log(process.argv[3]); +console.log(Object.keys(credentials).map(k => { + if (credentials[k].match(/\n/s)) + return (` ${k}: |\n${credentials[k]}`).replace(/\n/gs,"\n ") + else + return ` ${k}: "${credentials[k]}"` +}).join("\n")) \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/scripts/value.js b/app/multi-tenant/personal-space/cloud-cap-samples-java/scripts/value.js new file mode 100755 index 000000000..91c9ed3eb --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/scripts/value.js @@ -0,0 +1,38 @@ +#!/usr/bin/env node + +const yaml = require('yaml'); +const fs = require('fs'); + +const path = process.argv[2]; +if (!path) { + console.error('missing path'); + process.exit(1); +} + +const segments = path.split('.'); + +function printProperty(file) { + let valuesYaml; + try { + valuesYaml = fs.readFileSync(file, 'utf-8'); + } catch(error) { + return false; + } + const values = yaml.parse(valuesYaml); + + let o = values; + for (let segment of segments) { + o = o[segment]; + if (typeof o === "undefined" || o === null) return false; + } + + if (typeof o === "object") { + console.log(JSON.stringify(o)); + } else { + console.log(o); + } + + return true; +} + +printProperty('.values.yaml') || printProperty('values.yaml') || printProperty('chart/values.yaml') || process.exit(1); \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/admin-service.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/admin-service.cds new file mode 100644 index 000000000..defae7be8 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/admin-service.cds @@ -0,0 +1,376 @@ +using {sap.common.Languages as CommonLanguages} from '@sap/cds/common'; +using {my.bookshop as my} from '../db/index'; +using {sap.changelog as changelog} from 'com.sap.cds/change-tracking'; + +extend my.Orders with changelog.changeTracked; + +@path : 'admin' +service AdminService @(requires: [ + 'admin', + 'system-user' +]) { + entity Books as projection on my.Books excluding { reviews } actions { + action addToOrder(order_ID : UUID, quantity : Integer) returns Orders; + } + + entity Chapters as projection on my.Chapters; + entity Pages as projection on my.Pages; + + // Define a return type for the action result + type MoveAttachmentsResult { + failedObjectIds : array of String; + } + + entity Books.attachments as projection on my.Books.attachments + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self,up__ID:String,objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + } + annotate AdminService.Books.attachments with @( + Capabilities: {InsertRestrictions: {Insertable: up_.isAttachmentsUploadable}} + ); + + entity Books.references as projection on my.Books.references + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self,up__ID:String,objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + } + annotate AdminService.Books.references with @( + Capabilities: {InsertRestrictions: {Insertable: up_.isReferencesUploadable}} + ); + + entity Books.footnotes as projection on my.Books.footnotes + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self,up__ID:String,objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + } + + entity Pages.attachments as projection on my.Pages.attachments + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + entity Pages.references as projection on my.Pages.references + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + // Chapters projections + entity Chapters.attachments as projection on my.Chapters.attachments + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + entity Chapters.references as projection on my.Chapters.references + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + entity Chapters.footnotes as projection on my.Chapters.footnotes + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + // Side effects on parent entities: structural changes (add/delete) on attachment + // navigation collections trigger a re-read of the uploadable flag on the parent. + annotate AdminService.Books with @( + Common.SideEffects #sdmAttachmentsUploadable: { + SourceEntities: ['attachments'], + TargetProperties: ['isAttachmentsUploadable'] + }, + Common.SideEffects #sdmReferencesUploadable: { + SourceEntities: ['references'], + TargetProperties: ['isReferencesUploadable'] + } + ); + + // Pages footnotes projection + entity Pages.footnotes as projection on my.Pages.footnotes + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + entity Authors as projection on my.Authors; + entity Orders as select from my.Orders; + + @cds.persistence.skip + entity Upload @odata.singleton { + csv : LargeBinary @Core.MediaType : 'text/csv'; + } +} + +// Deep Search Items +annotate AdminService.Orders with @cds.search : { + OrderNo, + Items +}; + +annotate AdminService.OrderItems with @cds.search : {book}; + +annotate AdminService.Books with @cds.search : { + descr, + title +}; + +// Enable Fiori Draft for Orders +annotate AdminService.Orders with @odata.draft.enabled; +annotate AdminService.Books with @odata.draft.enabled; + +// workaround to enable the value help for languages +// Necessary because auto exposure is currently not working +// for if Languages is only referenced by the generated +// _texts table +extend service AdminService with { + entity Languages as projection on CommonLanguages; +} + +// Change-track orders and items +annotate AdminService.Orders { + OrderNo @changelog; +}; + +annotate AdminService.OrderItems { + quantity @changelog; + book @changelog: [ + book.title, + book.isbn + ] +}; + +// Assign identifiers to the tracked entities +annotate AdminService.Orders with @changelog: [OrderNo]; +annotate AdminService.OrderItems with @changelog: [ + parent.OrderNo, + book.title, + ]; diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/attachment-extension.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/attachment-extension.cds new file mode 100644 index 000000000..a3dd9c79c --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/attachment-extension.cds @@ -0,0 +1,155 @@ +using my.bookshop as my from '../db/books'; +using {sap.attachments.Attachments, sap.attachments.StatusCode} from`com.sap.cds/sdm`; +using { sap.common.CodeList } from '@sap/cds/common'; + +extend entity my.Books with { + attachments : Composition of many Attachments @SDM.Attachments:{maxCount: 4, maxCountError:'Only 4 attachments allowed.'}; + references : Composition of many Attachments @SDM.Attachments:{maxCount: 5, maxCountError:'Only 5 attachments allowed.'}; + footnotes : Composition of many Attachments; +} +extend entity my.Notebooks with { + attachments : Composition of many Attachments @SDM.Attachments:{maxCount: 4, maxCountError:'Only 4 attachments allowed.'}; +} +extend entity my.Chapters with { + attachments: Composition of many Attachments; + references: Composition of many Attachments; + footnotes: Composition of many Attachments; +} + +extend entity my.Pages with { + attachments: Composition of many Attachments; + references: Composition of many Attachments; + footnotes: Composition of many Attachments; +} + +entity Statuses @cds.autoexpose @readonly { + key code : StatusCode; + text : localized String(255); +} + +extend Attachments with { + statusText : Association to Statuses on statusText.code = $self.status; + customProperty1 : WDIRS_CodeList_TYPE + @SDM.Attachments.AdditionalProperty: { + name: 'Working:DocumentInfoRecordString' + } + @(title: 'DocumentInfoRecordString'); + customProperty2 : Integer + @SDM.Attachments.AdditionalProperty: { + name: 'Working:DocumentInfoRecordInt' + }; + customProperty3 : String + @SDM.Attachments.AdditionalProperty: { + name: 'abc:myId1' + } + @(title: 'id1'); + customProperty4 : String + @SDM.Attachments.AdditionalProperty: { + name: 'abc:myId2' + } + @(title: 'id2'); + customProperty5 : DateTime + @SDM.Attachments.AdditionalProperty: { + name: 'Working:DocumentInfoRecordDate' + } + @(title: 'DocumentInfoRecordDate'); + customProperty6 : Boolean + @SDM.Attachments.AdditionalProperty: { + name: 'Working:DocumentInfoRecordBoolean' + } + @(title: 'DocumentInfoRecordBoolean'); +} + +entity WDIRSCodeList : CodeList { + key code : String(30) @Common.Text : name @Common.TextArrangement: #TextFirst; +}; + +type WDIRS_CodeList_TYPE : Association to one WDIRSCodeList; + +annotate my.Books.attachments with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: {entity:'Statuses'} + ); +} + +annotate my.Books.references with { + content @Validation.Maximum : '30MB'; + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate my.Chapters.attachments with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate my.Chapters.references with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate my.Pages.attachments with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate my.Pages.references with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate my.Chapters.footnotes with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate my.Pages.footnotes with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/cat-service.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/cat-service.cds new file mode 100644 index 000000000..4402c589c --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/cat-service.cds @@ -0,0 +1,34 @@ +using {my.bookshop as my} from '../db/books'; + +@path : 'browse' +service CatalogService @(requires: ['any', 'system-user']) { + @readonly + entity Books as projection on my.Books excluding { + createdBy, + modifiedBy + } actions { + action addReview(rating : Integer, title : String, text : String) returns Reviews; + }; + + @readonly + entity Authors as projection on my.Authors; + + @readonly + entity Reviews as projection on my.Reviews; + + action submitOrder(book : Books : ID, quantity : Integer) returns { + stock : Integer + }; + + // access control restrictions + annotate Reviews with @restrict : [ + { + grant : 'READ', + to : 'any' + }, + { + grant : 'CREATE', + to : 'authenticated-user' + } + ]; +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/external.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/external.cds new file mode 100644 index 000000000..a64baa80e --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/external.cds @@ -0,0 +1,40 @@ +using { API_BUSINESS_PARTNER as external } from './external/API_BUSINESS_PARTNER'; + +/** + * Tailor the imported API to our needs... + */ +extend service external with { + + /** + * Add asynchronous eventing API + */ + @topic: 'sap.s4.beh.businesspartner.v1.BusinessPartner.Changed.v1' + event BusinessPartner.Changed { + BusinessPartner: String; + } + +} + +/** + * Simplified view on external addresses, which in addition acts as a table to store replicated external address data. + */ +@cds.persistence:{table,skip:false} //> create a table with the view's inferred signature +@cds.autoexpose //> auto-expose in services as targets for ValueHelps and joins +entity my.bookshop.Addresses as projection on external.A_BusinessPartnerAddress { + key AddressID as ID, + key BusinessPartner as businessPartner, + @readonly Country as country, + @readonly CityName as city, + @readonly PostalCode as postalCode, + @readonly StreetName as street, + @readonly HouseNumber as houseNumber, + false as tombstone: Boolean +} + +/* + * Extend Orders with references to replicated external Addresses + */ +using { my.bookshop.Orders } from '../db/index'; +extend Orders with { + shippingAddress : Association to my.bookshop.Addresses; +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/external/API_BUSINESS_PARTNER.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/external/API_BUSINESS_PARTNER.cds new file mode 100644 index 000000000..72c3173a0 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/external/API_BUSINESS_PARTNER.cds @@ -0,0 +1,3977 @@ +/* checksum : 33c2afcba69718abba5b5d612738f7cd */ +@cds.external : true +@m.IsDefaultEntityContainer : 'true' +@sap.message.scope.supported : 'true' +@sap.supported.formats : 'atom json xlsx' +service API_BUSINESS_PARTNER {}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Email Address' +entity API_BUSINESS_PARTNER.A_AddressEmailAddress { + /** + * Internal key for identifying a Business Address Services address. + * + * For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Address Number' + key AddressID : String(10) not null; + /** + * Internal key for identifying a person in Business Address Services. + * + * For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Person number' + key Person : String(10) not null; + @sap.display.format : 'NonNegative' + @sap.label : 'Sequence Number' + key OrdinalNumber : String(3) not null; + @sap.display.format : 'UpperCase' + @sap.label : 'Standard addr.' + @sap.quickinfo : 'Flag: this address is the default address' + IsDefaultEmailAddress : Boolean; + /** + * Internet mail address, also called e-mail address. + * + * Example: user.name@company.comThe Internet mail address is used to send mail via the Internet world-wide; the protocol used is SMTP (Simple Mail Transfer Protocol).The Internet mail address format is specified in various RFCs (Internet Request for Comment), including RFCs 821 and 822.This is not an IP address (192.56.30.6). + */ + @sap.label : 'Email Address' + EmailAddress : String(241); + /** + * This field is generated by the system from the complete Internet mail address and is stored in table ADR6. + * + * It contains the first 20 characters of the Internet mail address in normalized form, that is, without comment characters and converted into uppercase.The field cannot be maintained by the user or from an interface.The table ADR6 contains an index for this field.Using an Internet mail address, the corresponding key of table ADR6 and the owner of the address are determined (for example, business partner or user). + */ + @sap.display.format : 'UpperCase' + @sap.label : 'E-Mail Address' + @sap.quickinfo : 'E-Mail Address Search Field' + SearchEmailAddress : String(20); + /** + * Additional information about the communication connection + * + * You can maintain further information about the communication connection here. In the case of telephone numbers, for example, you can maintain the times at which the call recipient is available and those at which they are not, or you can specify whether the number is that of the secretary.The information is stored in table ADRT, regardless of language. + */ + @sap.label : 'Notes' + @sap.quickinfo : 'Communication link notes' + AddressCommunicationRemarkText : String(50); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Fax Number' +entity API_BUSINESS_PARTNER.A_AddressFaxNumber { + /** + * Internal key for identifying a Business Address Services address. + * + * For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Address Number' + key AddressID : String(10) not null; + /** + * Internal key for identifying a person in Business Address Services. + * + * For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Person number' + key Person : String(10) not null; + @sap.display.format : 'NonNegative' + @sap.label : 'Sequence Number' + key OrdinalNumber : String(3) not null; + /** + * If several addresses are maintained for one communication type, the user in the SAP System can be reached under one of these addresses. One address can be set as theStandard Address. + * + * The standard address is used for the following functions:When sending using the SMTP nodein SAPconnect, the home address of the communication type used is the one set as the sender address. The recipient can see this address in the sender information and can also reply directly to this address. The standard address is also transferred and can be used for incoming status notifications, for example.When sending using an RFC node in SAPconnect, the standard address of the communication type used is the one set as the sender address. The structure defined in the case of the RFC does not permit another address to be transferred, so the standard address is used for incoming status notifications too.The SAP users have the addresses of their exchange P.O. boxes in their standard communication type 'Internet Mail' as the home address and their Internet address in the SAP system as their standard address. Example:Home address: Bernard.Brown@Company.comStandard address: Bernard.Brown@System.Company.comSending using an SMTP nodeThe home address of the communication type 'Internet Mail' (Bernard.Brown@Company.com) is used as the sender address. If a reply is sent to this address the user receives directly in the exchange postbox.Sending using the RFC nodeThe standard address of the communication type 'Internet Mail' (Bernard.Brown@System.Company.com) is used as the sender address. If a reply is sent to this address, it arrives back to the SAP system.Example using a mail system groupThe users should get all messages in their Microsoft Exchange postboxes. In the SAP system the mail system group is activated for this using the setting "Send Messages to the Home Address".The address settings of the SAP users remain unchanged:Home address: Bernard.Brown@Company.comStandard address: Bernard.Brown@System.Company.comSending using an SMTP nodeThe home address of the communication type 'Internet Mail' (Bernard.Brown@Company.com) is used as the sender address. If a reply is sent to this address the user receives directly in the exchange postbox.Sending using the RFC nodeThe standard address of the communication type 'Internet Mail' (Bernard.Brown@System.Company.com) is used as the sender address. If a reply is sent to this address it arrives back in the SAP system. It is then forwarded using the mail system group to the home address and the user gets it in the exchange postbox. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Standard No.' + @sap.quickinfo : 'Standard Sender Address in this Communication Type' + IsDefaultFaxNumber : Boolean; + /** + * The country for the telephone number or fax number is maintained here. + * + * This specification is used to determine the correct country code. A normalized form of the telephone number or fax number is then derived and stored in a field for a program-driven search.In most cases, the telephone number or fax number refers directly to an address.If this is the case, when a new number is created, the country of the address is proposed.If this is not the case (for example, with address-independent communication data for a business partner), the country from the user parameter LND is proposed (if it is maintained). If the user parameter LND is not maintained, the country of the company address assigned in the user master data is proposed.If the country of the address changes, the country of the corresponding telephone number and fax address is not changed automatically.Example: A business partner moves abroad.If the telephone number is for a permanent connection, the telephone number also changes when the business partner moves and has to be maintained again in the system.If the telephone number is for a mobile telephone and the number is retained, the original country for this telephone number also has to be retained and must not be changed automatically to the new country of the address. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Country' + @sap.quickinfo : 'Country for telephone/fax number' + FaxCountry : String(3); + /** + * Fax number, consisting of dialling code and number, but without country dialling code. + * + * If the fax number consists of a company number and an extension, the extension must be entered in the field extension.Fax number, as it is to be dialled from within the same country.Enter the following for the number "01234/567-0":Fax: 01234/567Extension: 0Enter the following for the number "01234/567-891":Fax: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Fax: 012-345Extension: 678In the following cases, enter the complete number (without country dialing code) in the field Fax:No part of the number can be considered as an extension.You are not sure which part of the number can be considered as an extension. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Fax' + @sap.quickinfo : 'Fax number: dialling code+number' + FaxNumber : String(30); + /** + * Fax extension number + * + * If the fax number consists of a company number and an extension, the extension must be entered here.Enter the extensionThe following rules apply for the format of telephone and fax numbers:The length of the entries in the field Telephone and Extension (Fax and Extension) cannot be more than 24 characters in total.Leading spaces are not allowed in the field Telephone or Fax or in the field Extension.Valid characters are:Numbers (0123456789)Letters (ABCDEFGHIJKLMNOPQRSTUVWXYZ)Following other characters: /, (, ), - *, # and " " (space), but not as a leading space.If an + is entered as the first character, the system checks whether the specified number starts with a country code. If so, a warning message is displayed because the country code is automatically determined by the system and should not be stored in the Telephone number (Fax number) field.If an & is entered as the first character, the automatic check and formatting of the telephone number (fax number), as well as the determination of the country code, is suppressed.Enter the following for the number "01234/567-0":Fax: 01234/567Extension: 0Enter the following for the number "01234/567-891":Fax: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Fax: 012-345Extension: 678In the following cases, enter the complete number (without country dialing code) in the field Fax:No part of the number can be considered as an extension.You are not sure which part of the number can be considered as an extension. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Extension' + @sap.quickinfo : 'Fax no.: Extension' + FaxNumberExtension : String(10); + /** + * The content of this field is automatically calculated by the system based on fax number and country code components. + * + * This field is therefore not to be filled when Business Address Services function modules are called. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Fax Number' + @sap.quickinfo : 'Complete Number: Dialling Code+Number+Extension' + InternationalFaxNumber : String(30); + /** + * Additional information about the communication connection + * + * You can maintain further information about the communication connection here. In the case of telephone numbers, for example, you can maintain the times at which the call recipient is available and those at which they are not, or you can specify whether the number is that of the secretary.The information is stored in table ADRT, regardless of language. + */ + @sap.label : 'Notes' + @sap.quickinfo : 'Communication link notes' + AddressCommunicationRemarkText : String(50); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Home Page URL' +entity API_BUSINESS_PARTNER.A_AddressHomePageURL { + /** + * Internal key for identifying a Business Address Services address. + * + * For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Address Number' + key AddressID : String(10) not null; + /** + * Internal key for identifying a person in Business Address Services. + * + * For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Person number' + key Person : String(10) not null; + @sap.display.format : 'NonNegative' + @sap.label : 'Sequence Number' + key OrdinalNumber : String(3) not null; + @sap.display.format : 'Date' + @sap.label : 'from' + @sap.quickinfo : 'Valid-from date - in current Release only 00010101 possible' + key ValidityStartDate : Date not null; + @sap.display.format : 'UpperCase' + @sap.label : 'Standard addr.' + @sap.quickinfo : 'Flag: this address is the default address' + key IsDefaultURLAddress : Boolean not null; + @sap.display.format : 'UpperCase' + @sap.label : 'URI address' + @sap.quickinfo : 'URI address search field' + SearchURLAddress : String(50); + /** + * Additional information about the communication connection + * + * You can maintain further information about the communication connection here. In the case of telephone numbers, for example, you can maintain the times at which the call recipient is available and those at which they are not, or you can specify whether the number is that of the secretary.The information is stored in table ADRT, regardless of language. + */ + @sap.label : 'Notes' + @sap.quickinfo : 'Communication link notes' + AddressCommunicationRemarkText : String(50); + @sap.label : 'URI length' + @sap.quickinfo : 'URI field length' + URLFieldLength : Integer; + @sap.label : 'URI' + @sap.quickinfo : 'Universal Resource Identifier (URI)' + WebsiteURL : String(2048); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Phone Number' +entity API_BUSINESS_PARTNER.A_AddressPhoneNumber { + /** + * Internal key for identifying a Business Address Services address. + * + * For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Address Number' + key AddressID : String(10) not null; + /** + * Internal key for identifying a person in Business Address Services. + * + * For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Person number' + key Person : String(10) not null; + @sap.display.format : 'NonNegative' + @sap.label : 'Sequence Number' + key OrdinalNumber : String(3) not null; + /** + * The country for the telephone number or fax number is maintained here. + * + * This specification is used to determine the correct country code. A normalized form of the telephone number or fax number is then derived and stored in a field for a program-driven search.In most cases, the telephone number or fax number refers directly to an address.If this is the case, when a new number is created, the country of the address is proposed.If this is not the case (for example, with address-independent communication data for a business partner), the country from the user parameter LND is proposed (if it is maintained). If the user parameter LND is not maintained, the country of the company address assigned in the user master data is proposed.If the country of the address changes, the country of the corresponding telephone number and fax address is not changed automatically.Example: A business partner moves abroad.If the telephone number is for a permanent connection, the telephone number also changes when the business partner moves and has to be maintained again in the system.If the telephone number is for a mobile telephone and the number is retained, the original country for this telephone number also has to be retained and must not be changed automatically to the new country of the address. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Country' + @sap.quickinfo : 'Country for telephone/fax number' + DestinationLocationCountry : String(3); + /** + * If several addresses are maintained for one communication type, the user in the SAP System can be reached under one of these addresses. One address can be set as theStandard Address. + * + * The standard address is used for the following functions:When sending using the SMTP nodein SAPconnect, the home address of the communication type used is the one set as the sender address. The recipient can see this address in the sender information and can also reply directly to this address. The standard address is also transferred and can be used for incoming status notifications, for example.When sending using an RFC node in SAPconnect, the standard address of the communication type used is the one set as the sender address. The structure defined in the case of the RFC does not permit another address to be transferred, so the standard address is used for incoming status notifications too.The SAP users have the addresses of their exchange P.O. boxes in their standard communication type 'Internet Mail' as the home address and their Internet address in the SAP system as their standard address. Example:Home address: Bernard.Brown@Company.comStandard address: Bernard.Brown@System.Company.comSending using an SMTP nodeThe home address of the communication type 'Internet Mail' (Bernard.Brown@Company.com) is used as the sender address. If a reply is sent to this address the user receives directly in the exchange postbox.Sending using the RFC nodeThe standard address of the communication type 'Internet Mail' (Bernard.Brown@System.Company.com) is used as the sender address. If a reply is sent to this address, it arrives back to the SAP system.Example using a mail system groupThe users should get all messages in their Microsoft Exchange postboxes. In the SAP system the mail system group is activated for this using the setting "Send Messages to the Home Address".The address settings of the SAP users remain unchanged:Home address: Bernard.Brown@Company.comStandard address: Bernard.Brown@System.Company.comSending using an SMTP nodeThe home address of the communication type 'Internet Mail' (Bernard.Brown@Company.com) is used as the sender address. If a reply is sent to this address the user receives directly in the exchange postbox.Sending using the RFC nodeThe standard address of the communication type 'Internet Mail' (Bernard.Brown@System.Company.com) is used as the sender address. If a reply is sent to this address it arrives back in the SAP system. It is then forwarded using the mail system group to the home address and the user gets it in the exchange postbox. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Standard No.' + @sap.quickinfo : 'Standard Sender Address in this Communication Type' + IsDefaultPhoneNumber : Boolean; + /** + * Telephone number, consisting of dialling code and number, but without country dialling code. + * + * If the telephone number consists of a company number and an extension, the extension must be entered in the field extension.Telephone number, as it is dialled from within the country.For the number "01234/567-0" enter the following:Telephone: 01234/567Estension: 0For the number "01234/567-891" enter the following:Telephone: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Telepone: 012-345Extension: 678In the following cases enter the complete number (without country dialling code) in the field Telephone:No part of the number can be regarded as an extension.You are not sure which part of the number can be regarded as an extension. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Telephone' + @sap.quickinfo : 'Telephone no.: dialling code+number' + PhoneNumber : String(30); + /** + * Telephone extension number + * + * If the telephone number consists of a company number and an extension, the extension should be entered here.Enter the extension.The following rules apply for the format of telephone and fax numbers:The length of the entries in the field Telephone and Extension (Fax and Extension) cannot be more than 24 characters in total.Leading spaces are not allowed in the field Telephone or Fax or in the field Extension.Valid characters are:Numbers (0123456789)Letters (ABCDEFGHIJKLMNOPQRSTUVWXYZ)Following other characters: /, (, ), - *, # and " " (space), but not as a leading space.If an + is entered as the first character, the system checks whether the specified number starts with a country code. If so, a warning message is displayed because the country code is automatically determined by the system and should not be stored in the Telephone number (Fax number) field.If an & is entered as the first character, the automatic check and formatting of the telephone number (fax number), as well as the determination of the country code, is suppressed.For the number "01234/567-0" enter the following:Telephone: 01234/567Estension: 0For the number "01234/567-891" enter the following:Telephone: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Telepone: 012-345Extension: 678In the following cases enter the complete number (without country dialling code) in the field Telephone:No part of the number can be regarded as an extension.You are not sure which part of the number can be regarded as an extension. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Extension' + @sap.quickinfo : 'Telephone no.: Extension' + PhoneNumberExtension : String(10); + /** + * The content of this field is automatically calculated by the system based on the telephone number and country code components. + * + * This field is therefore not to be filled when Business Address Services function modules are called. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Telephone Number' + @sap.quickinfo : 'Complete Number: Dialling Code+Number+Extension' + InternationalPhoneNumber : String(30); + /** + * This field specifies whether the telephone number is a mobile telephone number. + * + * ' ' : The telephone number is a fixed-line telephone'1' : The telephone number is the standard fixed-line telephone'2' : The telephone nubmer is a mobile telephone'3' : The telephone number is the standard mobile telephoneEither the standard fixed-line telephone number or the standard mobile telephone number is also the standard telephone number (FLGDEFAULT = 'X').In older data sets, this field may have also have the value ' ' for the standard fixed-line telephone. In this case, however, FLGDEFAULT is always 'X'.In Customizing, you can specify whether the SMS-compatible indicator is to be proposed for new mobile telephone numbers created in dialog by choosing General Settings -> Set countries -> Define Mobile Telephone Attributes for each country. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Mobile phone' + @sap.quickinfo : 'Indicator: Telephone is a Mobile Telephone' + PhoneNumberType : String(1); + /** + * Additional information about the communication connection + * + * You can maintain further information about the communication connection here. In the case of telephone numbers, for example, you can maintain the times at which the call recipient is available and those at which they are not, or you can specify whether the number is that of the secretary.The information is stored in table ADRT, regardless of language. + */ + @sap.label : 'Notes' + @sap.quickinfo : 'Communication link notes' + AddressCommunicationRemarkText : String(50); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.creatable : 'false' +@sap.updatable : 'false' +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Contact Person Address' +entity API_BUSINESS_PARTNER.A_BPContactToAddress { + /** The business partner relationship number is an internal number that identifies the business partner relationship set. */ + @sap.display.format : 'UpperCase' + @sap.label : 'BP Relationship No.' + @sap.quickinfo : 'BP Relationship Number' + key RelationshipNumber : String(12) not null; + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartnerCompany : String(10) not null; + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartnerPerson : String(10) not null; + @sap.display.format : 'Date' + @sap.label : 'Valid To' + @sap.quickinfo : 'Validity Date (Valid To)' + key ValidityEndDate : Date not null; + /** + * Internal key for identifying a Business Address Services address. + * + * For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Address Number' + key AddressID : String(10) not null; + /** + * Internal key for identifying a Business Address Services address. + * + * For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Address Number' + AddressNumber : String(10); + /** + * Additional address field which is printed above the Street line. + * + * The Street address contains two lines above the street and two lines below the street.See Print the Street address. + */ + @sap.label : 'Street 3' + AdditionalStreetPrefixName : String(40); + /** + * Additional address field which is printed under the Street line. + * + * The Street address has two lines above the street and two lines below the steet.See Print the Street address. + */ + @sap.label : 'Street 5' + AdditionalStreetSuffixName : String(40); + /** + * Time zone as part of an address. + * + * The time zone is automatically determined by the system in address maintenance if time zone Customizing is maintained.It depends on the country and the region. (Region means state, province or county, depending on the country)The automatic determination is only made if there is no value in the time zone field. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Time zone' + @sap.quickinfo : 'Address time zone' + AddressTimeZone : String(6); + /** + * Part of the address (c/o = care of) if the recipient is different from the occupant and the names are not similar (e.g. subtenants). + * + * Put the country-specific code (e.g. c/o) in front of the name of the occupant. This is not automatically done in the print format, like the language-specific word "PO Box".John Smithc/o David BrownThis field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.label : 'c/o' + @sap.quickinfo : 'c/o name' + CareOfName : String(40); + @sap.display.format : 'UpperCase' + @sap.label : 'City Code' + @sap.quickinfo : 'City code for city/street file' + CityCode : String(12); + /** + * City name as part of the address. + * + * The city name is saved redundantly in another database field in upper- case letters, for search help.If the Postal regional structure ('city file') is active, the city name is checked against the Cities defined in the regional structure. + */ + @sap.label : 'City' + CityName : String(40); + /** + * Postal code that is assigned directly to one company (= company postal code = major customer postal code). + * + * This field is used for countries where major companies are assigned their own postal code by the national post office.This postal code has to be entered in the field "Company Postal Code". Postal codes for group major customers, however, have to be entered in the field "PO Box Postal Code", since individual customers with a shared postal code for group major customers are differentiated by means of their PO box. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Company Postal Code' + @sap.quickinfo : 'Company Postal Code (for Large Customers)' + CompanyPostalCode : String(10); + /** + * The country key contains information which the system uses to check entries such as the length of the postal code or bank account number. + * + * The two-character ISO code in accordance with ISO 3166, which is delivered by SAP as a default, is usually used.It could also be the vehicle license plate country-code or a typical country key, for example, in Germany the Federal statistics office key.The country keys are determined at system installation in the global settings.The definition of the country key in the SAP system does not have to match political or government entities.Since the country key does not have to correspond to the ISO code in all installations, programs that differ according to certain values of the country key cannot query the country key T005-LAND1, but have to program based on the ISO code T005 INTCA. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Country Key' + Country : String(3); + /** + * Specifies the county’s name + * + * This field is used to store the county’s name. You can enter the name of the county in this field. + */ + @sap.label : 'County' + County : String(40); + /** + * The delivery service is part of the PO box address. + * + * Some countries offer different services in addition to regular postal delivery and PO boxes, for example the Private Bag or Response Bag. If an address is related to one of these delivery services, the information about this particular delivery service has to be entered in the corresponding fields.In the field "Number of Delivery Service," the number of the Private Bag, Response Bag, or other relevant service has to be entered. Entering a number is not mandatory for each delivery service.For each address, either the information about the PO box or the information about the delivery service can be entered, but not both types of information at the same time.Mr PickeringPrivate Bag 106999Timaru 7942Delivery services will only be taken into account for address formatting in countries in which they are commonly used in addition to regular postal delivery and PO boxes, for example, in Australia, New Zealand, and the USA. In all other countries, these fields will not be taken into account for address formatting. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Delivery Service No.' + @sap.quickinfo : 'Number of Delivery Service' + DeliveryServiceNumber : String(10); + /** + * The delivery service is part of the PO box address. + * + * Some countries offer different services in addition to regular postal delivery and PO boxes, for example the Private Bag or Response Bag. If an address is related to one of these delivery services, the information about this particular delivery service has to be entered in the corresponding fields.In the field "Type of Delivery Service," the type of the delivery service has to be entered.For each address, either the information about the PO box or the information about the delivery service can be entered, but not both types of information at the same time.Mr PickeringPrivate Bag 106999Timaru 7942Delivery services will only be taken into account for address formatting in countries in which they are commonly used in addition to regular postal delivery and PO boxes, for example, in Australia, New Zealand, and the USA. In all other countries, these fields will not be taken into account for address formatting. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Delvry Serv Type' + @sap.quickinfo : 'Type of Delivery Service' + DeliveryServiceTypeCode : String(4); + /** + * City or District supplement + * + * In some countries, this entry is appended with a hyphen to the city name by the automatic address formatting, other countries, it is output on a line of its own or (e.g. in the USA) not printed.See the examples in the Address Layout Key documentation. + */ + @sap.label : 'District' + District : String(40); + /** + * Key for form of address text. + * + * You can also define a form of address text in Customizing.The form of address text can be maintained in different languages. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Title' + @sap.quickinfo : 'Form-of-Address Key' + @sap.creatable : 'false' + @sap.updatable : 'false' + FormOfAddress : String(4); + /** + * This field contains the full name or formatted name of a party. + * + * For organizations or document addresses, typically the fields Name1 and Name2 are concatenated.For persons the field contains the formatted name according to country specific rules. It corresponds e.g. to the content of the fields BUT000-NAME1_TEXT or ADRP-NAME_TEXT. + */ + @sap.label : 'Full Name' + @sap.quickinfo : 'Full name of a party (Bus. Partner, Org. Unit, Doc. address)' + @sap.creatable : 'false' + @sap.updatable : 'false' + FullName : String(80); + /** + * City of residence which is different from the postal city + * + * In some countries, the residential city is required if it differs from the postal city.In the USA, the official street indexes, against which data can be checked, are based on the residential city, not the postal city, which may be different.It is the same in France, where a postally correct address must contain the residential city in a separate line above the postal city, if it differs from the postal city.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.label : 'Different City' + @sap.quickinfo : 'City (different from postal city)' + HomeCityName : String(40); + /** + * House number as part of an address. + * + * It is printed in the Street line.Other supplementary street information can be entered in the House number supplement or one of the Street2, Street3, Street4 or Street5 fields. See Print the Street address.A house number (e.g. 117) or a house number with supplement (e.g. 117a), or a house number range (e.g. 16-20), can be maintained in this field. + */ + @sap.label : 'House Number' + HouseNumber : String(10); + /** + * House number supplement as part of an address, e.g. + * + * App. 17 orSuite 600.It is printed in the Street line.Further Street supplements can be put in one of the fields Street2, Street3, Street4 or Street5.See Print the Street address. + */ + @sap.label : 'Supplement' + @sap.quickinfo : 'House number supplement' + HouseNumberSupplementText : String(10); + /** + * The language key indicates + * + * - the language in which texts are displayed,- the language in which you enter texts,- the language in which the system prints texts. + */ + @sap.label : 'Language Key' + Language : String(2); + /** + * PO Box number as part of an address. + * + * Only enter the PO Box number in this field. The text "PO Box" is provided in the recipient language by the system when you print the address.When you print an address, the "Street address" and the "PO Box address" are distinguished. The print program determines which of them has priority if both are maintained in an address record.Besides the PO Box number, the PO Box address uses the following fields:PO Box postal code, if specified (otherwise the normal postal code)PO Box city, if specified (otherwise the normal city)PO Box region, if specified (otherwise the normal region)PO Box country, if specified (otherwise the normal country)If the address is a "PO Box" (without a number), do not fill the "PO Box" field. Select the "PO Box w/o Number" indicator instead.You can also enter a company postal code for organizational addresses, instead of a PO Box. A separate field is predefined for this entry.For general information and examples about address formatting, see the documentation on the Address Structure Key. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'PO Box' + POBox : String(10); + /** + * Different city for the PO Box as an address component. + * + * The PO Box city can be entered here if it is different from the address city.If the address is only a PO Box address, enter the city in the normal city field.If the address contains two different city names for the address and the PO Box address, use this field. + */ + @sap.label : 'PO Box City' + @sap.quickinfo : 'PO Box city' + POBoxDeviatingCityName : String(40); + /** + * Different PO Box country in address. + * + * The PO Box country can be entered here, if it is different from the street address country.If the address only has a PO Box address, the country is in the normal country field.Use this field if the address has two different country values for the street address and the PO Box address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'PO box country' + POBoxDeviatingCountry : String(3); + /** + * Different Region for PO Box in an address. + * + * Enter the PO Box Region here, if it differs from the street address region.If the address only has a PO Box address, the Region in in the normal Region field.Use this field if the address has two different Region values for the street address and the PO Box address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'PO Box Region' + @sap.quickinfo : 'Region for PO Box (Country, State, Province, ...)' + POBoxDeviatingRegion : String(3); + /** + * PO Box address without PO Box number flag. + * + * Only the word 'PO Box' is output in PO Box addresses without PO Box number.Set this flag for a PO Box address without PO Box number.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'PO Box w/o No.' + @sap.quickinfo : 'Flag: PO Box Without Number' + POBoxIsWithoutNumber : Boolean; + /** + * The PO box lobby is part of the PO box address. + * + * In some countries, entering a PO box, postal code and city is not sufficient to uniquely identify a PO box, because the same PO box number is assigned multiple times in some cities.Therefore, additional information might be required to determine the post office of the PO box in question. This information can be entered in the field "PO Box Lobby."Mr NellingPO Box 4099HighfieldTimaru 7942The PO box lobby will only be taken into account for address formatting in countries in which it is commonly used in addition to regular postal delivery and PO boxes, for example, in Canada or New Zealand. In all other countries, this field will not be taken into account for address formatting. + */ + @sap.label : 'PO Box Lobby' + POBoxLobbyName : String(40); + /** + * Postal code that is required for a unique assignment of the PO box. + * + * This field is used for countries where a different postal code applies to mail that is sent to the PO box rather than to the street address of a particular business partner.Postal codes for group major customers also have to be entered in the field for the PO box postal code since individual customers with a shared postal code for group major customers are differentiated by means of the PO box. Postal codes for major customers (= company postal codes), however, are assigned to one customer only and have to be entered in the field 'Company Postal Code'. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'PO Box Postal Code' + POBoxPostalCode : String(10); + /** + * Internal key for identifying a person in Business Address Services. + * + * For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Person number' + @sap.creatable : 'false' + @sap.updatable : 'false' + Person : String(10); + /** + * Postal code as part of the address + * + * If different postal codes are maintained for the PO Box and Street address of an address, this field contains the Street address postal code. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Postal Code' + @sap.quickinfo : 'City Postal Code' + PostalCode : String(10); + /** + * Communication method with which you can exchange documents and messages with a business partner. + * + * In Business Address Services, you can specify a standard communication method that can be used by programs to determine the means of communication for sending messages.One business partner wants all messages by fax, another by e-mail.The application context can restrict the possible methods of communication. For example, invitations should perhaps only be sent by post because of enclosures, whereas minutes can be sent by post, fax or e-mail.Communication strategies can be defined for this purpose and applied in application contexts. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Comm. Method' + @sap.quickinfo : 'Communication Method (Key) (Business Address Services)' + PrfrdCommMediumType : String(3); + /** + * In some countries, the region forms part of the address. The meaning depends on the country. + * + * The automatic address formatting function prints the region in addresses in the USA, Canada, Italy, Brazil or Australia, and the county in Great Britain.For more information, see the examples in the documentation on the Address Layout Key.Meaning of the regional code in ...Australia -> ProvinceBrazil -> StateCanada -> ProvinceGermany -> StateGreat Britain -> CountyItaly -> ProvinceJapan -> PrefectureSwitzerland -> CantonUSA -> State + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Region' + @sap.quickinfo : 'Region (State, Province, County)' + Region : String(3); + /** + * Street name as part of the address. + * + * The street name is saved, redundantly in upper case in another database field, for search help purposes.There are other fields for address parts which can be printed above or below the street. See Print the Street address.The house number and other supplements are usually maintained in their own fields. See Formatting the Street line. + */ + @sap.label : 'Street' + StreetName : String(60); + /** + * Additional address field which is printed above the Street line. + * + * The Street address contains two lines above the street and two lines below the street.See Print the Street address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.label : 'Street 2' + StreetPrefixName : String(40); + /** + * Additional address field which is printed below the Street line. + * + * The Street address contains two lines above the street and two lines below the street.See Print the Street address. + */ + @sap.label : 'Street 4' + StreetSuffixName : String(40); + /** Specifies the tax jurisdiction. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Jurisdiction' + TaxJurisdiction : String(15); + /** + * Sales and distribution: + * + * Regional zone of Goods recipient.Purchasing:Regional zone of supplier.You can define regional zones to suit the requirements of your own business and country.Sales and distributionthe system automatically proposes a suitable route by using the transportation zone of the goods recipient in combination with other information about the delivery, such as theCountries of origin and destinationShipping conditionsTransportation groupIn the USA, for example, you can define regional zones to correspond to the US postal zip codes. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Transportation Zone' + @sap.quickinfo : 'Transportation zone to or from which the goods are delivered' + TransportZone : String(10); + @cds.ambiguous : 'missing on condition?' + to_EmailAddress : Association to many API_BUSINESS_PARTNER.A_AddressEmailAddress { }; + @cds.ambiguous : 'missing on condition?' + to_FaxNumber : Association to many API_BUSINESS_PARTNER.A_AddressFaxNumber { }; + @cds.ambiguous : 'missing on condition?' + to_MobilePhoneNumber : Association to many API_BUSINESS_PARTNER.A_AddressPhoneNumber { }; + @cds.ambiguous : 'missing on condition?' + to_PhoneNumber : Association to many API_BUSINESS_PARTNER.A_AddressPhoneNumber { }; + @cds.ambiguous : 'missing on condition?' + to_URLAddress : Association to many API_BUSINESS_PARTNER.A_AddressHomePageURL { }; +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.creatable : 'false' +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Function and Department' +entity API_BUSINESS_PARTNER.A_BPContactToFuncAndDept { + /** The business partner relationship number is an internal number that identifies the business partner relationship set. */ + @sap.display.format : 'UpperCase' + @sap.label : 'BP Relationship No.' + @sap.quickinfo : 'BP Relationship Number' + key RelationshipNumber : String(12) not null; + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartnerCompany : String(10) not null; + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartnerPerson : String(10) not null; + @sap.display.format : 'Date' + @sap.label : 'Valid To' + @sap.quickinfo : 'Validity Date (Valid To)' + key ValidityEndDate : Date not null; + /** + * Identifies the function that a person has within a company. + * + * This is a contact person attribute that you can define in Customizing.Personnel managerSecretary + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Function' + @sap.quickinfo : 'Function of partner' + ContactPersonFunction : String(4); + /** + * Name of the department of a business partner for your internal usage. + * + * The name given by the business partner to this particular department may differ from the name that you use. You can enter the name given by the business partner in the field company department.This is a contact person attribute that you can define in Customizing.For your purposes, the department name is "Sales". The business partner names the same department "Sales South". + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Department' + ContactPersonDepartment : String(4); + /** + * Telephone number, consisting of dialling code and number, but without country dialling code. + * + * If the telephone number consists of a company number and an extension, the extension must be entered in the field extension.Telephone number, as it is dialled from within the country.For the number "01234/567-0" enter the following:Telephone: 01234/567Estension: 0For the number "01234/567-891" enter the following:Telephone: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Telepone: 012-345Extension: 678In the following cases enter the complete number (without country dialling code) in the field Telephone:No part of the number can be regarded as an extension.You are not sure which part of the number can be regarded as an extension. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Telephone' + @sap.quickinfo : 'Telephone no.: dialling code+number' + PhoneNumber : String(30); + /** + * Telephone extension number + * + * If the telephone number consists of a company number and an extension, the extension should be entered here.Enter the extension.The following rules apply for the format of telephone and fax numbers:The length of the entries in the field Telephone and Extension (Fax and Extension) cannot be more than 24 characters in total.Leading spaces are not allowed in the field Telephone or Fax or in the field Extension.Valid characters are:Numbers (0123456789)Letters (ABCDEFGHIJKLMNOPQRSTUVWXYZ)Following other characters: /, (, ), - *, # and " " (space), but not as a leading space.If an + is entered as the first character, the system checks whether the specified number starts with a country code. If so, a warning message is displayed because the country code is automatically determined by the system and should not be stored in the Telephone number (Fax number) field.If an & is entered as the first character, the automatic check and formatting of the telephone number (fax number), as well as the determination of the country code, is suppressed.For the number "01234/567-0" enter the following:Telephone: 01234/567Estension: 0For the number "01234/567-891" enter the following:Telephone: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Telepone: 012-345Extension: 678In the following cases enter the complete number (without country dialling code) in the field Telephone:No part of the number can be regarded as an extension.You are not sure which part of the number can be regarded as an extension. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Extension' + @sap.quickinfo : 'Telephone no.: Extension' + PhoneNumberExtension : String(10); + /** + * Fax number, consisting of dialling code and number, but without country dialling code. + * + * If the fax number consists of a company number and an extension, the extension must be entered in the field extension.Fax number, as it is to be dialled from within the same country.Enter the following for the number "01234/567-0":Fax: 01234/567Extension: 0Enter the following for the number "01234/567-891":Fax: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Fax: 012-345Extension: 678In the following cases, enter the complete number (without country dialing code) in the field Fax:No part of the number can be considered as an extension.You are not sure which part of the number can be considered as an extension. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Fax' + @sap.quickinfo : 'Fax number: dialling code+number' + FaxNumber : String(30); + /** + * Fax extension number + * + * If the fax number consists of a company number and an extension, the extension must be entered here.Enter the extensionThe following rules apply for the format of telephone and fax numbers:The length of the entries in the field Telephone and Extension (Fax and Extension) cannot be more than 24 characters in total.Leading spaces are not allowed in the field Telephone or Fax or in the field Extension.Valid characters are:Numbers (0123456789)Letters (ABCDEFGHIJKLMNOPQRSTUVWXYZ)Following other characters: /, (, ), - *, # and " " (space), but not as a leading space.If an + is entered as the first character, the system checks whether the specified number starts with a country code. If so, a warning message is displayed because the country code is automatically determined by the system and should not be stored in the Telephone number (Fax number) field.If an & is entered as the first character, the automatic check and formatting of the telephone number (fax number), as well as the determination of the country code, is suppressed.Enter the following for the number "01234/567-0":Fax: 01234/567Extension: 0Enter the following for the number "01234/567-891":Fax: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Fax: 012-345Extension: 678In the following cases, enter the complete number (without country dialing code) in the field Fax:No part of the number can be considered as an extension.You are not sure which part of the number can be considered as an extension. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Extension' + @sap.quickinfo : 'Fax no.: Extension' + FaxNumberExtension : String(10); + /** + * Internet mail address, also called e-mail address. + * + * Example: user.name@company.comThe Internet mail address is used to send mail via the Internet world-wide; the protocol used is SMTP (Simple Mail Transfer Protocol).The Internet mail address format is specified in various RFCs (Internet Request for Comment), including RFCs 821 and 822.This is not an IP address (192.56.30.6). + */ + @sap.label : 'Email Address' + EmailAddress : String(241); + /** + * A relationship may exist between two business partners. The business partner relationship category characterizes the features of the relationship. + * + * A distinction is made between a one-way and an undirected business partner relationship category. In a one-way relationship category, the relationship extends from one partner to another, but not vice versa.Marriage (undirected)Employee (one-way)Contact person (one-way) + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Relationship Cat.' + @sap.quickinfo : 'Business Partner Relationship Category' + RelationshipCategory : String(6); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Address Usage' +entity API_BUSINESS_PARTNER.A_BuPaAddressUsage { + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartner : String(10) not null; + @odata.Type : 'Edm.DateTimeOffset' + @sap.label : 'Valid To' + @sap.quickinfo : 'Validity End of a Business Partner Address Usage' + key ValidityEndDate : DateTime not null; + /** + * Business partner attribute, which you can use to distinguish between various addresses by defining the address usage for communication with business partners. + * + * Maintain the usage types for addresses (address types) in Customizing.You can create a short description and a name for the address type.When maintaining business partners you can use the function address usage to assign business partner addresses to address types.If necessary, you can set the indicator for multiple use in Customizing.Correspondence addressDelivery address + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Address Type' + key AddressUsage : String(10) not null; + /** + * Internal key for identifying a Business Address Services address. + * + * For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Address Number' + key AddressID : String(10) not null; + @odata.Type : 'Edm.DateTimeOffset' + @sap.label : 'Valid From' + @sap.quickinfo : 'Validity Start of a Business Partner Address Usage' + ValidityStartDate : DateTime; + /** + * Establishes which is the standard address for an address usage. + * + * Several addresses per period can be assigned to an address usage.If this is the case, then this indicator controls which of the assigned addresses should be the standard address of the relevant usage. This is determined automatically when the address usage is accessed. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Standard Usage' + @sap.quickinfo : 'Indicator: Standard Address Usage' + StandardUsage : Boolean; + /** + * You can use authorization groups to stipulate which business partners a user is allowed to process. + * + * Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization Group' + AuthorizationGroup : String(4); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Identification' +entity API_BUSINESS_PARTNER.A_BuPaIdentification { + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartner : String(10) not null; + /** + * A document (such as an ID card or driver's license) or an entry in a system of records (such as a commercial register) whose key can be stored as an attribute for a business partner. + * + * The identification type is for classifying identification numbers.You can define the identification types and their descriptions in Customizing.You can also specify for which business partner category an ID type should be valid.If necessary, assign the identification type to an Identification Category.You can only assign one identification type to an identification category. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Identification Type' + key BPIdentificationType : String(6) not null; + /** Number that serves to identify a business partner, such as driver's license, or ID card number. */ + @sap.display.format : 'UpperCase' + @sap.label : 'ID number' + @sap.quickinfo : 'Identification Number' + key BPIdentificationNumber : String(60) not null; + /** Institution that adminsters or assigns an ID number. */ + @sap.label : 'Responsible Institn' + @sap.quickinfo : 'Responsible Institution for ID Number' + BPIdnNmbrIssuingInstitute : String(40); + /** Date on which the ID number was registered or assigned by the appropriate authority. */ + @sap.display.format : 'Date' + @sap.label : 'Entry date' + @sap.quickinfo : 'Date of Entry for ID Number' + BPIdentificationEntryDate : Date; + /** Country in which an ID number was assigned, or in which the number is valid. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Country' + @sap.quickinfo : 'Country in Which ID Number is Valid or Was Assigned' + Country : String(3); + /** + * In some countries, the region forms part of the address. The meaning depends on the country. + * + * The automatic address formatting function prints the region in addresses in the USA, Canada, Italy, Brazil or Australia, and the county in Great Britain.For more information, see the examples in the documentation on the Address Layout Key.Meaning of the regional code in ...Australia -> ProvinceBrazil -> StateCanada -> ProvinceGermany -> StateGreat Britain -> CountyItaly -> ProvinceJapan -> PrefectureSwitzerland -> CantonUSA -> State + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Region' + @sap.quickinfo : 'Region (State, Province, County)' + Region : String(3); + /** This date marks the start of validity of an ID number. */ + @sap.display.format : 'Date' + @sap.label : 'Valid from' + @sap.quickinfo : 'Validity Start for ID Number' + ValidityStartDate : Date; + /** This date marks the end of validity of an ID number. */ + @sap.display.format : 'Date' + @sap.label : 'Valid To' + @sap.quickinfo : 'Validity End for ID Number' + ValidityEndDate : Date; + /** + * You can use authorization groups to stipulate which business partners a user is allowed to process. + * + * Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization Group' + AuthorizationGroup : String(4); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Industry' +entity API_BUSINESS_PARTNER.A_BuPaIndustry { + /** + * Describes an industry. + * + * An industry is a classification of companies according to their main business activity. For example, you can use Commerce, Banking, Services, Industry, Healthcare, Public Sector, Media, and so on, as industries.You can define industries along with their descriptions in Customizing.Assign the industry key to an industry key system. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Industry' + key IndustrySector : String(10) not null; + /** + * Serves to combine and categorize several industries into a group. + * + * You can create different industry systems, each with its own catalog of industries, whereby an industry can be assigned to several industry systems.You have to select one industry system as the standard industry system. This is then automatically displayed in the initial screen for the maintenance of industry data.You can define an industry system along with its description in Customizing. You can assign several industry systems to a business partner.If you choose the button All Industry Systems, you can access all the industry systems defined in the Customizing using the input help. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Industry System' + key IndustrySystemType : String(4) not null; + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartner : String(10) not null; + /** + * Identifies the industry in an industry system that can be defined as the standard industry. + * + * It is recommended that you define an industry within an industry system as the standard industry, because only the standard industries can be determined at the interfaces to BW or the APIs, for example.This means that even if only one industry exists within an industry system, it should be indicated as the standard industry as this this information cannot be determined otherwise. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Standard Industry' + @sap.quickinfo : 'Industry is Standard for BP in Industry System' + IsStandardIndustry : String(1); + @sap.label : 'Description' + IndustryKeyDescription : String(100); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Business Partner' +entity API_BUSINESS_PARTNER.A_BusinessPartner { + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartner : String(10) not null; + /** Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer' + @sap.quickinfo : 'Customer Number' + @sap.creatable : 'false' + @sap.updatable : 'false' + Customer : String(10); + /** Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Supplier' + @sap.quickinfo : 'Account Number of Supplier' + @sap.creatable : 'false' + @sap.updatable : 'false' + Supplier : String(10); + /** + * Key for academic title. + * + * You can define a key for an academic title in Customizing. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Academic Title 1' + @sap.quickinfo : 'Academic Title: Key' + AcademicTitle : String(4); + /** + * You can use authorization groups to stipulate which business partners a user is allowed to process. + * + * Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization Group' + AuthorizationGroup : String(4); + /** + * Category under which a business partner is classified. + * + * You can distinguish between the following business partner categories:OrganizationNatural personGroup of natural persons or organizationsThe processing screens for the business partner categories are set up differently.So, for example, the screen for an organization contains the field Legal form, but this is not needed in the screen for a natural person. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'BP Category' + @sap.quickinfo : 'Business Partner Category' + BusinessPartnerCategory : String(1); + @sap.creatable : 'false' + @sap.updatable : 'false' + BusinessPartnerFullName : String(81); + /** + * Classification assigned when creating a business partner. + * + * Assign each business partner to a grouping when you create the business partner. The grouping determines the number range. You cannot change the assignment afterwards.You can define the groupings, their descriptions, the associated number range and other attributes in Customizing.You can define standard groupings for the internal and the external number assignment.For each grouping create a number range.When you create a business partner, the entry in the grouping field determines whether and how an entry is made in the business partner number field. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Grouping' + @sap.quickinfo : 'Business Partner Grouping' + BusinessPartnerGrouping : String(4); + @sap.creatable : 'false' + @sap.updatable : 'false' + BusinessPartnerName : String(81); + @sap.label : 'BP GUID' + @sap.quickinfo : 'Business Partner GUID' + @sap.creatable : 'false' + @sap.updatable : 'false' + BusinessPartnerUUID : UUID; + /** + * Correspondence language (written) for business partners in the 'Person' category. Maintain the correspondence language for business partners in the 'Organization' and 'Group' category with the address (communication). + * + * When transferring data (direct input), make sure that for a'Person', the field 'LANGU_CORR' and for an'Organization' or "Group" the field 'LANGU'has an entry. + */ + @sap.label : 'Correspondence lang.' + @sap.quickinfo : 'Business Partner: Correspondence Language' + CorrespondenceLanguage : String(2); + @sap.display.format : 'UpperCase' + @sap.label : 'Created By' + @sap.quickinfo : 'User who created the object' + @sap.creatable : 'false' + @sap.updatable : 'false' + CreatedByUser : String(12); + @sap.display.format : 'Date' + @sap.label : 'Created on' + @sap.quickinfo : 'Date on which the object was created' + @sap.creatable : 'false' + @sap.updatable : 'false' + CreationDate : Date; + @sap.label : 'Created at' + @sap.quickinfo : 'Time at which the object was created' + @sap.creatable : 'false' + @sap.updatable : 'false' + CreationTime : Time; + @sap.label : 'First Name' + @sap.quickinfo : 'First Name of Business Partner (Person)' + FirstName : String(40); + /** + * Key for form of address text. + * + * You can also define a form of address text in Customizing.The form of address text can be maintained in different languages. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Title' + @sap.quickinfo : 'Form-of-Address Key' + FormOfAddress : String(4); + /** + * An industry sector is the term used to classify a company according to its main business activity. + * + * You can assign an industry sector to business partners in the category 'Organization'RetailBanksServicesIndustryHealth servicePublic sectorMedia + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Industry sector' + Industry : String(10); + /** + * Here you enter the first 7 digits of the international location number. + * + * The International Location Number (ILN) is assigned (in Germany by the Centrale for Coorganisation GmbH)) when a company is founded. It consists of 13 digits, the last digit being the check digit. There are two categories of location numbers:Participants who only need an ILN to cleary and unmistakably identify themselves for communication with the business partner are given a category 1 ILN. This cannot be used to identify articles by means of EAN.Participants who wish to assign the location numbers for their own enterprise areas are given a category 2 ILN. For a category 2 ILN, digits 1 to 7 are described as basis number. This is used as basis for the creation of article numbers (EAN). + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Int. location no. 1' + @sap.quickinfo : 'International location number (part 1)' + InternationalLocationNumber1 : String(7); + /** + * Here, you enter digits 8-12 of the 13-digit international location number. + * + * The international location number (ILN) is assigned when establishing a company (by the "Zentrale für Coorganisation GmbH" in Germany). It consists of 13 digits, the last of which is the check digit. There are two types of international location numbers:Subscribers who only need one ILN to identify themselves in communication with the business partner are given an ILN of type 1. These cannot be used for identifying articles by means of EAN.Subscribers who need to assign location numbers for their own company areas are given an ILN of type 2. Positions 1 through 7 of the ILN type 2 are known as the basis number. This basis number forms the basis for article numbers (EAN). + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Int. location no. 2' + @sap.quickinfo : 'International location number (Part 2)' + InternationalLocationNumber2 : String(5); + @sap.display.format : 'UpperCase' + @sap.label : 'Female' + @sap.quickinfo : 'Selection: Business partner is female' + IsFemale : Boolean; + @sap.display.format : 'UpperCase' + @sap.label : 'Male' + @sap.quickinfo : 'Selection: Business partner is male' + IsMale : Boolean; + /** + * Indicator through which a distinction between natural and legal persons can be made during tax reporting. + * + * Is used in Italy and Mexico ,among other countries.Brasil: If the indicator is not set, 'CGC' is relevant in tax number 1. If the indicator is set, 'CPF' is relevant in tax number 2.Colombia: In the case of some natural persons, the NIT number does not have a check digit. In this case you should set this indicator and the check is deactivated. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Natural Person' + @sap.quickinfo : 'Business Partner Is a Natural Person Under the Tax Laws' + IsNaturalPerson : String(1); + @sap.display.format : 'UpperCase' + @sap.label : 'Unknown' + @sap.quickinfo : 'Selection: Sex of business partner is not known' + IsSexUnknown : Boolean; + @sap.display.format : 'UpperCase' + @sap.label : 'Gender' + @sap.quickinfo : 'Gender of Business Partner (Person)' + GenderCodeName : String(1); + /** + * Language for verbal communication with a business partner. + * + * This language may differ from the language(s) defined for written correspondence. + */ + @sap.label : 'Language' + @sap.quickinfo : 'Business partner: Language' + Language : String(2); + @sap.display.format : 'Date' + @sap.label : 'Changed on' + @sap.quickinfo : 'Date when object was last changed' + @sap.creatable : 'false' + @sap.updatable : 'false' + LastChangeDate : Date; + @sap.label : 'Changed at' + @sap.quickinfo : 'Time at which object was last changed' + @sap.creatable : 'false' + @sap.updatable : 'false' + LastChangeTime : Time; + @sap.display.format : 'UpperCase' + @sap.label : 'Changed by' + @sap.quickinfo : 'Last user to change object' + @sap.creatable : 'false' + @sap.updatable : 'false' + LastChangedByUser : String(12); + @sap.label : 'Last Name' + @sap.quickinfo : 'Last Name of Business Partner (Person)' + LastName : String(40); + /** + * Denotes certain legal norms that are of significance for the organization of a company. + * + * For business partners in the category "Organization", you can state the legal form of the company. This is for information purposes only.Stock corporation (AG in Germany)Limited liability company (GmbH in Germany) + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Legal form' + @sap.quickinfo : 'BP: Legal form of organization' + LegalForm : String(2); + /** First name field for business partners in the Organization category. */ + @sap.label : 'Name 1' + @sap.quickinfo : 'Name 1 of organization' + OrganizationBPName1 : String(40); + /** Second name field for business partners in the Organization category. */ + @sap.label : 'Name 2' + @sap.quickinfo : 'Name 2 of organization' + OrganizationBPName2 : String(40); + /** Third name field for business partners in the Organization category. */ + @sap.label : 'Name 3' + @sap.quickinfo : 'Name 3 of organization' + OrganizationBPName3 : String(40); + /** Fourth name field for business partners in the Organization category. */ + @sap.label : 'Name 4' + @sap.quickinfo : 'Name 4 of organization' + OrganizationBPName4 : String(40); + /** + * Indicates the official registration of a company in the Commercial Register. + * + * If a company is not officially registered in the Commercial Register, it has to use some type of text addition, such as foundation pending, when referring to the legal form. + */ + @sap.display.format : 'Date' + @sap.label : 'Date founded' + @sap.quickinfo : 'Date organization founded' + OrganizationFoundationDate : Date; + /** + * Term for the end of bankruptcy proceedings. + * + * This date also indicates that the company no longer exists. + */ + @sap.display.format : 'Date' + @sap.label : 'Liquidation date' + @sap.quickinfo : 'Liquidation date of organization' + OrganizationLiquidationDate : Date; + /** Denotes the term that you define for a business partner, and via which you can restrict the search for a business partner in the business partner search or in the locator. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Search term 1' + @sap.quickinfo : 'Search term 1 for business partner' + SearchTerm1 : String(20); + /** Denotes the term that you define for a business partner, and via which you can restrict the search for a business partner in the business partner search or in the locator. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Search term 2' + @sap.quickinfo : 'Search term 2 for business partner' + SearchTerm2 : String(20); + @sap.label : 'Other Last Name' + @sap.quickinfo : 'Other Last Name of a Person' + AdditionalLastName : String(40); + @sap.display.format : 'Date' + @sap.label : 'Date of Birth' + @sap.quickinfo : 'Date of Birth of Business Partner' + BirthDate : Date; + @sap.label : 'Birthplace' + @sap.quickinfo : 'Birthplace of business partner' + BusinessPartnerBirthplaceName : String(40); + /** If the business partner is blocked centrally, certain activities cannot be executed. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Central Block' + @sap.quickinfo : 'Central Block for Business Partner' + BusinessPartnerIsBlocked : Boolean; + /** + * You can use the business partner type to group business partners according to your own criteria in Customizing (IMG). + * + * In Customizing you can show or hide fields for data entry, depending on the requirements of the relevant business partner type.Select a business partner type. You can obtain help by pressing the F4 key. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'BP Type' + @sap.quickinfo : 'Business Partner Type' + BusinessPartnerType : String(4); + @sap.creatable : 'false' + @sap.updatable : 'false' + ETag : String(26); + /** First name field for business partners in the Group category. */ + @sap.label : 'Name 1' + @sap.quickinfo : 'Name 1 (group)' + GroupBusinessPartnerName1 : String(40); + /** Second name field for business partners in the Group category. */ + @sap.label : 'Name 2' + @sap.quickinfo : 'Name 2 (group)' + GroupBusinessPartnerName2 : String(40); + /** + * Internal key for identifying the address for communication data that spans all addresses in Business Partner. + * + * For more information on the significance and usage of the address number, see the documentation for Business Address Services (BAS). + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Address Number' + @sap.creatable : 'false' + @sap.updatable : 'false' + IndependentAddressID : String(10); + /** The check digit is derived from a special check digit procedure from digits of the previous international location numbers. In this way, you can check whether the ILN entered is actually valid. */ + @sap.display.format : 'NonNegative' + @sap.label : 'Check digit' + @sap.quickinfo : 'Check digit for the international location number' + InternationalLocationNumber3 : String(1); + @sap.label : 'Middle Name' + @sap.quickinfo : 'Middle Name or Second Forename of a Person' + MiddleName : String(40); + /** + * The name format rule country and the name format rule key together uniquely identify a formatting rule. + * + * A country can have several formats which correspond to different rules. Formatting rules describe the format of a person name. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Country for format' + @sap.quickinfo : 'Country for Name Format Rule' + NameCountry : String(3); + /** See Name format. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Name Format' + @sap.quickinfo : 'Name format' + NameFormat : String(2); + /** + * States the complete name of a person. + * + * The complete name is generally generated and saved by the Business Address Services (BAS) according to country-specific rules from the individual name components (without the form of address).If, during the formatting of an address, you want to use an alternative name, you can manually format the alternative name here. + */ + @sap.label : 'Full Name' + PersonFullName : String(80); + /** + * Internal key for identifying a person in Business Address Services. + * + * For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Person number' + @sap.creatable : 'false' + @sap.updatable : 'false' + PersonNumber : String(10); + /** + * Establishes if the business partner is meant to be archived. + * + * If the indicator is set, the relevant business partner can be archived from the view of the business partner administration.If the check of the data to be archived shows, for example, that there are still active business transactions the archiving of the business partner data is prevented even if the indicator is set.If the indicator is not set, the business partner will not be taken into consideration during archiving. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Archiving Flag' + @sap.quickinfo : 'Central Archiving Flag' + IsMarkedForArchiving : Boolean; + /** + * Business partner number from an external system or a legacy system. + * + * If the current business partner is known under a different number in an external system, you can store this number here for information purposes.Direct input gives you the option of maintaining a business partner by specifying the external business partner number. If you maintain business partner data in your legacy system, you can transmit changes made to business partners to the SAP system without having to know the SAP business partner number in the legacy system. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'External BP Number' + @sap.quickinfo : 'Business Partner Number in External System' + BusinessPartnerIDByExtSystem : String(20); + /** Company ID standard for the whole group. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Trading Partner No.' + @sap.quickinfo : 'Company ID of trading partner' + TradingPartner : String(6); + @cds.ambiguous : 'missing on condition?' + to_BuPaIdentification : Association to many API_BUSINESS_PARTNER.A_BuPaIdentification { }; + @cds.ambiguous : 'missing on condition?' + to_BuPaIndustry : Association to many API_BUSINESS_PARTNER.A_BuPaIndustry { }; + @cds.ambiguous : 'missing on condition?' + to_BusinessPartnerAddress : Association to many API_BUSINESS_PARTNER.A_BusinessPartnerAddress { }; + @cds.ambiguous : 'missing on condition?' + to_BusinessPartnerBank : Association to many API_BUSINESS_PARTNER.A_BusinessPartnerBank { }; + @cds.ambiguous : 'missing on condition?' + to_BusinessPartnerContact : Association to many API_BUSINESS_PARTNER.A_BusinessPartnerContact { }; + @cds.ambiguous : 'missing on condition?' + to_BusinessPartnerRole : Association to many API_BUSINESS_PARTNER.A_BusinessPartnerRole { }; + @cds.ambiguous : 'missing on condition?' + to_BusinessPartnerTax : Association to many API_BUSINESS_PARTNER.A_BusinessPartnerTaxNumber { }; + @cds.ambiguous : 'missing on condition?' + to_Customer : Association to API_BUSINESS_PARTNER.A_Customer { }; + @cds.ambiguous : 'missing on condition?' + to_Supplier : Association to API_BUSINESS_PARTNER.A_Supplier { }; +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Address' +entity API_BUSINESS_PARTNER.A_BusinessPartnerAddress { + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartner : String(10) not null; + /** + * Internal key for identifying a Business Address Services address. + * + * For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Address Number' + key AddressID : String(10) not null; + @odata.Type : 'Edm.DateTimeOffset' + @sap.label : 'Valid From' + @sap.quickinfo : 'Validity Start of a Business Partner Address' + ValidityStartDate : DateTime; + @odata.Type : 'Edm.DateTimeOffset' + @sap.label : 'Valid To' + @sap.quickinfo : 'Validity End of a Business Partner Address' + ValidityEndDate : DateTime; + /** + * You can use authorization groups to stipulate which business partners a user is allowed to process. + * + * Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization Group' + AuthorizationGroup : String(4); + @sap.label : 'GUID of a Business Partner Address' + @sap.heading : '' + @sap.creatable : 'false' + @sap.updatable : 'false' + AddressUUID : UUID; + /** + * Additional address field which is printed above the Street line. + * + * The Street address contains two lines above the street and two lines below the street.See Print the Street address. + */ + @sap.label : 'Street 3' + AdditionalStreetPrefixName : String(40); + /** + * Additional address field which is printed under the Street line. + * + * The Street address has two lines above the street and two lines below the steet.See Print the Street address. + */ + @sap.label : 'Street 5' + AdditionalStreetSuffixName : String(40); + /** + * Time zone as part of an address. + * + * The time zone is automatically determined by the system in address maintenance if time zone Customizing is maintained.It depends on the country and the region. (Region means state, province or county, depending on the country)The automatic determination is only made if there is no value in the time zone field. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Time zone' + @sap.quickinfo : 'Address time zone' + AddressTimeZone : String(6); + /** + * Part of the address (c/o = care of) if the recipient is different from the occupant and the names are not similar (e.g. subtenants). + * + * Put the country-specific code (e.g. c/o) in front of the name of the occupant. This is not automatically done in the print format, like the language-specific word "PO Box".John Smithc/o David BrownThis field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.label : 'c/o' + @sap.quickinfo : 'c/o name' + CareOfName : String(40); + @sap.display.format : 'UpperCase' + @sap.label : 'City Code' + @sap.quickinfo : 'City code for city/street file' + CityCode : String(12); + /** + * City name as part of the address. + * + * The city name is saved redundantly in another database field in upper- case letters, for search help.If the Postal regional structure ('city file') is active, the city name is checked against the Cities defined in the regional structure. + */ + @sap.label : 'City' + CityName : String(40); + /** + * Postal code that is assigned directly to one company (= company postal code = major customer postal code). + * + * This field is used for countries where major companies are assigned their own postal code by the national post office.This postal code has to be entered in the field "Company Postal Code". Postal codes for group major customers, however, have to be entered in the field "PO Box Postal Code", since individual customers with a shared postal code for group major customers are differentiated by means of their PO box. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Company Postal Code' + @sap.quickinfo : 'Company Postal Code (for Large Customers)' + CompanyPostalCode : String(10); + /** + * The country key contains information which the system uses to check entries such as the length of the postal code or bank account number. + * + * The two-character ISO code in accordance with ISO 3166, which is delivered by SAP as a default, is usually used.It could also be the vehicle license plate country-code or a typical country key, for example, in Germany the Federal statistics office key.The country keys are determined at system installation in the global settings.The definition of the country key in the SAP system does not have to match political or government entities.Since the country key does not have to correspond to the ISO code in all installations, programs that differ according to certain values of the country key cannot query the country key T005-LAND1, but have to program based on the ISO code T005 INTCA. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Country Key' + Country : String(3); + /** + * Specifies the county’s name + * + * This field is used to store the county’s name. You can enter the name of the county in this field. + */ + @sap.label : 'County' + County : String(40); + /** + * The delivery service is part of the PO box address. + * + * Some countries offer different services in addition to regular postal delivery and PO boxes, for example the Private Bag or Response Bag. If an address is related to one of these delivery services, the information about this particular delivery service has to be entered in the corresponding fields.In the field "Number of Delivery Service," the number of the Private Bag, Response Bag, or other relevant service has to be entered. Entering a number is not mandatory for each delivery service.For each address, either the information about the PO box or the information about the delivery service can be entered, but not both types of information at the same time.Mr PickeringPrivate Bag 106999Timaru 7942Delivery services will only be taken into account for address formatting in countries in which they are commonly used in addition to regular postal delivery and PO boxes, for example, in Australia, New Zealand, and the USA. In all other countries, these fields will not be taken into account for address formatting. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Delivery Service No.' + @sap.quickinfo : 'Number of Delivery Service' + DeliveryServiceNumber : String(10); + /** + * The delivery service is part of the PO box address. + * + * Some countries offer different services in addition to regular postal delivery and PO boxes, for example the Private Bag or Response Bag. If an address is related to one of these delivery services, the information about this particular delivery service has to be entered in the corresponding fields.In the field "Type of Delivery Service," the type of the delivery service has to be entered.For each address, either the information about the PO box or the information about the delivery service can be entered, but not both types of information at the same time.Mr PickeringPrivate Bag 106999Timaru 7942Delivery services will only be taken into account for address formatting in countries in which they are commonly used in addition to regular postal delivery and PO boxes, for example, in Australia, New Zealand, and the USA. In all other countries, these fields will not be taken into account for address formatting. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Delvry Serv Type' + @sap.quickinfo : 'Type of Delivery Service' + DeliveryServiceTypeCode : String(4); + /** + * City or District supplement + * + * In some countries, this entry is appended with a hyphen to the city name by the automatic address formatting, other countries, it is output on a line of its own or (e.g. in the USA) not printed.See the examples in the Address Layout Key documentation. + */ + @sap.label : 'District' + District : String(40); + /** + * Key for form of address text. + * + * You can also define a form of address text in Customizing.The form of address text can be maintained in different languages. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Title' + @sap.quickinfo : 'Form-of-Address Key' + @sap.creatable : 'false' + @sap.updatable : 'false' + FormOfAddress : String(4); + /** + * This field contains the full name or formatted name of a party. + * + * For organizations or document addresses, typically the fields Name1 and Name2 are concatenated.For persons the field contains the formatted name according to country specific rules. It corresponds e.g. to the content of the fields BUT000-NAME1_TEXT or ADRP-NAME_TEXT. + */ + @sap.label : 'Full Name' + @sap.quickinfo : 'Full name of a party (Bus. Partner, Org. Unit, Doc. address)' + @sap.creatable : 'false' + @sap.updatable : 'false' + FullName : String(80); + /** + * City of residence which is different from the postal city + * + * In some countries, the residential city is required if it differs from the postal city.In the USA, the official street indexes, against which data can be checked, are based on the residential city, not the postal city, which may be different.It is the same in France, where a postally correct address must contain the residential city in a separate line above the postal city, if it differs from the postal city.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.label : 'Different City' + @sap.quickinfo : 'City (different from postal city)' + HomeCityName : String(40); + /** + * House number as part of an address. + * + * It is printed in the Street line.Other supplementary street information can be entered in the House number supplement or one of the Street2, Street3, Street4 or Street5 fields. See Print the Street address.A house number (e.g. 117) or a house number with supplement (e.g. 117a), or a house number range (e.g. 16-20), can be maintained in this field. + */ + @sap.label : 'House Number' + HouseNumber : String(10); + /** + * House number supplement as part of an address, e.g. + * + * App. 17 orSuite 600.It is printed in the Street line.Further Street supplements can be put in one of the fields Street2, Street3, Street4 or Street5.See Print the Street address. + */ + @sap.label : 'Supplement' + @sap.quickinfo : 'House number supplement' + HouseNumberSupplementText : String(10); + /** + * The language key indicates + * + * - the language in which texts are displayed,- the language in which you enter texts,- the language in which the system prints texts. + */ + @sap.label : 'Language Key' + Language : String(2); + /** + * PO Box number as part of an address. + * + * Only enter the PO Box number in this field. The text "PO Box" is provided in the recipient language by the system when you print the address.When you print an address, the "Street address" and the "PO Box address" are distinguished. The print program determines which of them has priority if both are maintained in an address record.Besides the PO Box number, the PO Box address uses the following fields:PO Box postal code, if specified (otherwise the normal postal code)PO Box city, if specified (otherwise the normal city)PO Box region, if specified (otherwise the normal region)PO Box country, if specified (otherwise the normal country)If the address is a "PO Box" (without a number), do not fill the "PO Box" field. Select the "PO Box w/o Number" indicator instead.You can also enter a company postal code for organizational addresses, instead of a PO Box. A separate field is predefined for this entry.For general information and examples about address formatting, see the documentation on the Address Structure Key. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'PO Box' + POBox : String(10); + /** + * Different city for the PO Box as an address component. + * + * The PO Box city can be entered here if it is different from the address city.If the address is only a PO Box address, enter the city in the normal city field.If the address contains two different city names for the address and the PO Box address, use this field. + */ + @sap.label : 'PO Box City' + @sap.quickinfo : 'PO Box city' + POBoxDeviatingCityName : String(40); + /** + * Different PO Box country in address. + * + * The PO Box country can be entered here, if it is different from the street address country.If the address only has a PO Box address, the country is in the normal country field.Use this field if the address has two different country values for the street address and the PO Box address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'PO box country' + POBoxDeviatingCountry : String(3); + /** + * Different Region for PO Box in an address. + * + * Enter the PO Box Region here, if it differs from the street address region.If the address only has a PO Box address, the Region in in the normal Region field.Use this field if the address has two different Region values for the street address and the PO Box address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'PO Box Region' + @sap.quickinfo : 'Region for PO Box (Country, State, Province, ...)' + POBoxDeviatingRegion : String(3); + /** + * PO Box address without PO Box number flag. + * + * Only the word 'PO Box' is output in PO Box addresses without PO Box number.Set this flag for a PO Box address without PO Box number.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'PO Box w/o No.' + @sap.quickinfo : 'Flag: PO Box Without Number' + POBoxIsWithoutNumber : Boolean; + /** + * The PO box lobby is part of the PO box address. + * + * In some countries, entering a PO box, postal code and city is not sufficient to uniquely identify a PO box, because the same PO box number is assigned multiple times in some cities.Therefore, additional information might be required to determine the post office of the PO box in question. This information can be entered in the field "PO Box Lobby."Mr NellingPO Box 4099HighfieldTimaru 7942The PO box lobby will only be taken into account for address formatting in countries in which it is commonly used in addition to regular postal delivery and PO boxes, for example, in Canada or New Zealand. In all other countries, this field will not be taken into account for address formatting. + */ + @sap.label : 'PO Box Lobby' + POBoxLobbyName : String(40); + /** + * Postal code that is required for a unique assignment of the PO box. + * + * This field is used for countries where a different postal code applies to mail that is sent to the PO box rather than to the street address of a particular business partner.Postal codes for group major customers also have to be entered in the field for the PO box postal code since individual customers with a shared postal code for group major customers are differentiated by means of the PO box. Postal codes for major customers (= company postal codes), however, are assigned to one customer only and have to be entered in the field 'Company Postal Code'. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'PO Box Postal Code' + POBoxPostalCode : String(10); + /** + * Internal key for identifying a person in Business Address Services. + * + * For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Person number' + @sap.creatable : 'false' + @sap.updatable : 'false' + Person : String(10); + /** + * Postal code as part of the address + * + * If different postal codes are maintained for the PO Box and Street address of an address, this field contains the Street address postal code. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Postal Code' + @sap.quickinfo : 'City Postal Code' + PostalCode : String(10); + /** + * Communication method with which you can exchange documents and messages with a business partner. + * + * In Business Address Services, you can specify a standard communication method that can be used by programs to determine the means of communication for sending messages.One business partner wants all messages by fax, another by e-mail.The application context can restrict the possible methods of communication. For example, invitations should perhaps only be sent by post because of enclosures, whereas minutes can be sent by post, fax or e-mail.Communication strategies can be defined for this purpose and applied in application contexts. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Comm. Method' + @sap.quickinfo : 'Communication Method (Key) (Business Address Services)' + PrfrdCommMediumType : String(3); + /** + * In some countries, the region forms part of the address. The meaning depends on the country. + * + * The automatic address formatting function prints the region in addresses in the USA, Canada, Italy, Brazil or Australia, and the county in Great Britain.For more information, see the examples in the documentation on the Address Layout Key.Meaning of the regional code in ...Australia -> ProvinceBrazil -> StateCanada -> ProvinceGermany -> StateGreat Britain -> CountyItaly -> ProvinceJapan -> PrefectureSwitzerland -> CantonUSA -> State + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Region' + @sap.quickinfo : 'Region (State, Province, County)' + Region : String(3); + /** + * Street name as part of the address. + * + * The street name is saved, redundantly in upper case in another database field, for search help purposes.There are other fields for address parts which can be printed above or below the street. See Print the Street address.The house number and other supplements are usually maintained in their own fields. See Formatting the Street line. + */ + @sap.label : 'Street' + StreetName : String(60); + /** + * Additional address field which is printed above the Street line. + * + * The Street address contains two lines above the street and two lines below the street.See Print the Street address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + */ + @sap.label : 'Street 2' + StreetPrefixName : String(40); + /** + * Additional address field which is printed below the Street line. + * + * The Street address contains two lines above the street and two lines below the street.See Print the Street address. + */ + @sap.label : 'Street 4' + StreetSuffixName : String(40); + /** Specifies the tax jurisdiction. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Jurisdiction' + TaxJurisdiction : String(15); + /** + * Sales and distribution: + * + * Regional zone of Goods recipient.Purchasing:Regional zone of supplier.You can define regional zones to suit the requirements of your own business and country.Sales and distributionthe system automatically proposes a suitable route by using the transportation zone of the goods recipient in combination with other information about the delivery, such as theCountries of origin and destinationShipping conditionsTransportation groupIn the USA, for example, you can define regional zones to correspond to the US postal zip codes. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Transportation Zone' + @sap.quickinfo : 'Transportation zone to or from which the goods are delivered' + TransportZone : String(10); + /** + * Address number from an external system or a legacy system + * + * If the current address has a different number in an external system, you can save this number here for information purposes.In direct input you are able to maintain an address for a business partner by stating the external address number. If your business partner data is maintained in a legacy system, you can thus transmit changes to a BP address to the SAP system without having to know the SAP address number in the legacy system. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'External Address No.' + @sap.quickinfo : 'Address number in external system' + AddressIDByExternalSystem : String(20); + @cds.ambiguous : 'missing on condition?' + to_AddressUsage : Association to many API_BUSINESS_PARTNER.A_BuPaAddressUsage { }; + @cds.ambiguous : 'missing on condition?' + to_EmailAddress : Association to many API_BUSINESS_PARTNER.A_AddressEmailAddress { }; + @cds.ambiguous : 'missing on condition?' + to_FaxNumber : Association to many API_BUSINESS_PARTNER.A_AddressFaxNumber { }; + @cds.ambiguous : 'missing on condition?' + to_MobilePhoneNumber : Association to many API_BUSINESS_PARTNER.A_AddressPhoneNumber { }; + @cds.ambiguous : 'missing on condition?' + to_PhoneNumber : Association to many API_BUSINESS_PARTNER.A_AddressPhoneNumber { }; + @cds.ambiguous : 'missing on condition?' + to_URLAddress : Association to many API_BUSINESS_PARTNER.A_AddressHomePageURL { }; +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Bank' +entity API_BUSINESS_PARTNER.A_BusinessPartnerBank { + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartner : String(10) not null; + /** + * Key identifying a business partner's bank details. + * + * Enter a bank details ID for each separate set of bank details for a business partner.Business Partner: H. MillerBD-ID Fin.institution Acct no. 0001 Chemical Bank, NYC 56234560002 Chemical Bank, NYC 56231220003 First Bank of Pittsburgh ...Business partner: T.Wolsey and Co.BD-ID Fin.institution Acct no.GIR0 Citibank, Charleston ...GIR1 Chemical Bank, NYC ... + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Bank details ID' + key BankIdentification : String(4) not null; + /** + * Identifies the country in which the bank is based. + * + * The country key determines according to which rules the remaining bank data (for example, bank number and bank account number) is checked. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Bank Country' + @sap.quickinfo : 'Bank Country Key' + BankCountryKey : String(3); + /** The name under which the bank operates. */ + @sap.label : 'Bank Name' + @sap.creatable : 'false' + @sap.updatable : 'false' + BankName : String(60); + /** + * The bank key (under which the bank data is stored in the appropriate country) is specified in this field. + * + * The country-specific meaning of this bank key is specified when defining country key.Normally banks have a bank number, which then also appears in the control data of the bank.In certain countries the bank account number assumes this function; in such a case there would be no bank numbers, the bank details are then under the account number.For data medium exchange it can be useful to be able create banks for foreign business partners without a bank number, even if the country in question has bank numbers. In such cases the bank key can be assigned internally.If the bank data is under another key, such as the SWIFT code for example, numbers can also be assigned externally. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Bank Key' + BankNumber : String(15); + /** + * Uniquely identifies a bank throughout the world. + * + * SWIFT stands for Society for Worldwide Interbank Financial Telecommunication.BIC stands for Bank Identifier Code.This globally unique code can be used in international payment transactions to identify the bank without the need to specify an address or bank number. Specification of the SWIFT code/BIC is mainly relevant for automatic payment transactions. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'SWIFT/BIC' + @sap.quickinfo : 'SWIFT/BIC for International Payments' + @sap.creatable : 'false' + @sap.updatable : 'false' + SWIFTCode : String(11); + /** + * Brazil, France, Spain, Portugal and Italy + * + * The field contains a check key for the combination bank number and bank account number.USAIn USA this field is used to differentiate between a savings and a current account (if no value is entered, the default value 01 is used).01 Current account02 Savings account03 Loan account04 General ledgerJapanIn Japan this field specifies the type of account. This information is is copied from the payment medium print program into payment medium. The following is an example of the account types used:01 FUTSU (similar to a savings account)02 TOUZA (similar to a current account)04 CHOCHIKU (similar to an investment account)09 Other types of bank accountsSouth AfricaIn South Africa this field specifies the type of account. The information entered here is forwarded to the bank that carries out the payment order. The following account types are permitted in ABC format:01 Current (Cheque) Account02 Savings Account03 Transmission Account04 Bond Account06 Subscription Share AccountArgentinaIn Argentina this field specifies the type of account:CC Current Account (Cuenta corriente)CA Saving Account (Caja de ahorro)CE Special Saving Account (Caja de ahorro especial)CS Salary Account (Cuenta sueldos)VenezuelaIn Venezuela this field specifies the type of account:CC Checking Account (Cuenta corriente)CA Saving Account (Cuenta de ahorro)CE Special Saving Account (Cuenta de ahorro especial)CS Salary Account (Cuenta sueldos)MexicoIn Mexico this field contains a two-digit key for classifying the bank account (for example, as a savings or current account). This key have different definitions, depending on the bank.NoteFor countries that are not listed here, this field can be used for account-specific information. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Bank Control Key' + BankControlKey : String(2); + /** Here you can enter another name that the payment program can use if the name of the account holder is not the same as the name of the Business Partner. */ + @sap.label : 'Account Holder' + @sap.quickinfo : 'Account Holder Name' + BankAccountHolderName : String(60); + @sap.label : 'Account Name' + @sap.quickinfo : 'Name of Bank Account' + BankAccountName : String(40); + @odata.Type : 'Edm.DateTimeOffset' + @sap.label : 'Valid From' + @sap.quickinfo : 'Validity Start of Business Partner Bank Details' + ValidityStartDate : DateTime; + @odata.Type : 'Edm.DateTimeOffset' + @sap.label : 'Valid To' + @sap.quickinfo : 'Validity End of Business Partner Bank Details' + ValidityEndDate : DateTime; + /** + * A uniform standardized ID number for representing bank details that is in accordance with the ECBS (European Committee for Banking Standards). An IBAN has a maximum of 34 alphanumeric characters and is a combination of the following elements: + * + * Country key of the bank (ISO code)Two-digit check numberCountry-specific account number (in Germany this consists of the bank number and account number, in France the bank number, account number and check key).The IBAN not only makes international payments easier, in some countries it has advantages for domestic payments as well. Depending on the country, it can mean advantages for value and fees.The IBAN can be maintained in parallel with the bank details but does not replace them. It is stored under the master data of the business partner and can then be used when creating the payment medium.Since it is only the bank that has the account that may generate the IBAN corresponding to an account number, the SAP system only generates a proposal. You can confirm or change this proposal. If no proposal is generated, enter the IBAN manually.An IBAN in Belgium may look like this:Electronic Form:BE62510007547061Printed form, as it would appear on an invoice:IBAN BE62 5100 0754 7061 + */ + @sap.display.format : 'UpperCase' + @sap.label : 'IBAN' + @sap.quickinfo : 'IBAN (International Bank Account Number)' + IBAN : String(34); + @sap.display.format : 'Date' + @sap.label : 'IBAN valid from' + @sap.quickinfo : 'Validity start of IBAN' + IBANValidityStartDate : Date; + /** This field contains the number under which the account is managed at the bank. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Bank Account' + @sap.quickinfo : 'Bank Account Number' + BankAccount : String(18); + /** + * Additional details for the bank details of the business partner. + * + * In some countries the data for the bank details of the business partner (bank number, bank account number, name of the account holder) have to supplemented by other details in order to be able to use certain payment processes. This supplementary details are defined here.If additional data is required for the bank details for payment transactions in your country (see the following examples), enter the reference information.If for an automatic debit the bank requires the reference number of the collection authorization in Norway or Great Britain, specify this number here.In Great Britain when making payments to an account in a 'Building Society' you must specify which number payment recipient has. These details must be defined in the reference field, whereas the fields Bank Key and Account Number are to be used for the bank details of the 'Building Society'.In Great Britain when entering a building society account number, the name of the building society should also be maintained in the system. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Reference Details' + @sap.quickinfo : 'Reference Details for Bank Details' + BankAccountReferenceText : String(20); + /** + * States that the bank has collection authorization from the business partner for the account. + * + * Set this indicator if the bank has collection authorization.Note for Accounts Receivable (FI-AR)If this indicator is not set, there is no bank collection.Note for Contract Accounts Receivable and Payable (FI-CA)This indicator is not relevant. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Collect.author.' + @sap.quickinfo : 'Indicator: Collection Authorization' + CollectionAuthInd : Boolean; + /** Name of the city as a part of the address. */ + @sap.label : 'City' + @sap.creatable : 'false' + @sap.updatable : 'false' + CityName : String(35); + /** + * You can use authorization groups to stipulate which business partners a user is allowed to process. + * + * Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization Group' + AuthorizationGroup : String(4); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Contact' +entity API_BUSINESS_PARTNER.A_BusinessPartnerContact { + /** The business partner relationship number is an internal number that identifies the business partner relationship set. */ + @sap.display.format : 'UpperCase' + @sap.label : 'BP Relationship No.' + @sap.quickinfo : 'BP Relationship Number' + key RelationshipNumber : String(12) not null; + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartnerCompany : String(10) not null; + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartnerPerson : String(10) not null; + @sap.display.format : 'Date' + @sap.label : 'Valid To' + @sap.quickinfo : 'Validity Date (Valid To)' + key ValidityEndDate : Date not null; + @sap.display.format : 'Date' + @sap.label : 'Valid From' + @sap.quickinfo : 'Validity Date (Valid From)' + ValidityStartDate : Date; + /** + * States whether the relationship is a standard relationship. + * + * If several relationships of the BP relationship category contact person have been defined for, you can set the indicator standard relationship for one of these relationships.A relationship that is marked as a standard relationship can be used whenA certain scenario automatically selects a contact personThe contact person responsible is not knownYou can give this indicator to only one business partner relationship of a BP relationship category for a particular period. Another relationship of the same relationship category can be indicated as the standard relationship only if the periods for the relationship do not overlap or coincide. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Standard' + @sap.quickinfo : 'Standard Relationship' + IsStandardRelationship : Boolean; + /** + * A relationship may exist between two business partners. The business partner relationship category characterizes the features of the relationship. + * + * A distinction is made between a one-way and an undirected business partner relationship category. In a one-way relationship category, the relationship extends from one partner to another, but not vice versa.Marriage (undirected)Employee (one-way)Contact person (one-way) + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Relationship Cat.' + @sap.quickinfo : 'Business Partner Relationship Category' + RelationshipCategory : String(6); + @cds.ambiguous : 'missing on condition?' + to_ContactAddress : Association to many API_BUSINESS_PARTNER.A_BPContactToAddress { }; + @cds.ambiguous : 'missing on condition?' + to_ContactRelationship : Association to API_BUSINESS_PARTNER.A_BPContactToFuncAndDept { }; +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Role' +entity API_BUSINESS_PARTNER.A_BusinessPartnerRole { + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartner : String(10) not null; + /** + * Function that a business partner takes on, depending on a business transaction. + * + * You can define business partner roles along with their attributes in Customizing.You can create an alphanumeric, 6-digit key for the BP role. You can also choose a title as the short form and a description as the long form for the role text.Screen control in the dialog takes place by assigning a BP view.A program can access specific business partner roles for a business partner using thebusiness partner role category . The role categories are also in the TB003 table. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'BP Role' + key BusinessPartnerRole : String(6) not null; + @odata.Type : 'Edm.DateTimeOffset' + @sap.label : 'Valid From' + @sap.quickinfo : 'Validity Start of a BP Role' + ValidFrom : DateTime; + @odata.Type : 'Edm.DateTimeOffset' + @sap.label : 'Valid To' + @sap.quickinfo : 'Validity End of a BP Role' + ValidTo : DateTime; + /** + * You can use authorization groups to stipulate which business partners a user is allowed to process. + * + * Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization Group' + AuthorizationGroup : String(4); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Tax Number' +entity API_BUSINESS_PARTNER.A_BusinessPartnerTaxNumber { + /** Key identifying a business partner in the SAP system. The key is unique within a client. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Business Partner' + @sap.quickinfo : 'Business Partner Number' + key BusinessPartner : String(10) not null; + /** Specifies the tax number category. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number Category' + key BPTaxType : String(4) not null; + /** Specifies the tax number. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax number' + @sap.quickinfo : 'Business Partner Tax Number' + BPTaxNumber : String(20); + /** + * Specifies the tax number. + * + * You can enter up to 60 characters in this field. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number' + @sap.quickinfo : 'Business Partner Tax Number' + BPTaxLongNumber : String(60); + /** + * You can use authorization groups to stipulate which business partners a user is allowed to process. + * + * Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization Group' + AuthorizationGroup : String(4); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.creatable : 'false' +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Customer' +entity API_BUSINESS_PARTNER.A_Customer { + /** Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer' + @sap.quickinfo : 'Customer Number' + key Customer : String(10) not null; + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); + /** + * Indicates if the processing of billing documents is blocked for the customer in all sales areas (company-wide, for example). + * + * You can define different kinds of block, according to the needs of your organization. You can, for example, automatically block the processing of all credit memos to a certain customer, pending manual approval. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Billing Block' + @sap.quickinfo : 'Central Billing Block for Customer' + BillingIsBlockedForCustomer : String(2); + /** Name with which the user who entered the master record was logged on in the R/3 System. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Created by' + @sap.quickinfo : 'Name of Person who Created the Object' + @sap.creatable : 'false' + @sap.updatable : 'false' + CreatedByUser : String(12); + /** Date on which the master record, or the part of the master record being viewed, was created. */ + @sap.display.format : 'Date' + @sap.label : 'Created on' + @sap.quickinfo : 'Date on which the Record Was Created' + @sap.creatable : 'false' + @sap.updatable : 'false' + CreationDate : Date; + /** + * The account group is a classifying feature within customer master records. The account group determines: + * + * in which number range the customer account number should be;whether the number is assigned by the user or by the system;which specifications are necessary or possible in the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account Group' + @sap.quickinfo : 'Customer Account Group' + CustomerAccountGroup : String(4); + /** + * Specifies a classification of the customer (for example, classifies the customer as a bulk purchaser). + * + * The classifications are freely definable according to the needs of your organization. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer Classific.' + @sap.quickinfo : 'Customer Classification' + CustomerClassification : String(2); + @sap.display.format : 'UpperCase' + @sap.label : 'Customer Name' + @sap.quickinfo : 'Customer Full Name' + @sap.creatable : 'false' + @sap.updatable : 'false' + CustomerFullName : String(220); + @sap.label : 'Name of Customer' + @sap.creatable : 'false' + @sap.updatable : 'false' + CustomerName : String(80); + /** + * Indicates if delivery processing is blocked for the customer in all sales areas (company-wide, for example). + * + * You can define different kinds of block, according to the needs of your organization. You can, for example, automatically block all deliveries to a certain customer for credit reasons. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Delivery block' + @sap.quickinfo : 'Central delivery block for the customer' + DeliveryIsBlocked : String(2); + /** + * Denotes a natural person. + * + * In the following countries, the system needs to know whether the taxpayer is a legal or natural person so that it can check the tax numbers correctly:BrazilBulgariaColombiaCroatiaGreeceItalyMexicoPeruSloveniaThailandUkraineThe flag is also used in conjunction with the Statement of Payments to Natural Persons report, as used in the Czech Republic and in Slovakia. This report only covers customers and vendors for whom you have set this indicator.In South Korea, it is used in conjunction with the Generic Withholding Tax Reporting program. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Natural Person' + NFPartnerIsNaturalPerson : String(1); + /** + * Indicates if sales order processing is blocked for the customer in all sales areas (company-wide, for example). + * + * If you block sales order processing, the block counts for the following partner functions of the customer:Sold-to partyShip-to partyPayerIf you want to process an order where the ship-to party differs from the sold-to party, and the ship-to party is blocked, you cannot process the order.You can define different kinds of block, according to the needs of your organization. You can, for example, automatically block all free of charge deliveries and credit memo requests for a certain customer, pending manual approval before further processing can take place. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Order Block' + @sap.quickinfo : 'Central Order Block for Customer' + OrderIsBlockedForCustomer : String(2); + /** + * Indicates that the account is blocked for posting for all company codes. + * + * If you set this indicator, the system prevents users from posting items to this account and issues an error message to inform them that the account is blocked. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Posting Block' + @sap.quickinfo : 'Central Posting Block' + PostingIsBlocked : Boolean; + /** Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Supplier' + @sap.quickinfo : 'Account Number of Supplier' + Supplier : String(10); + /** + * If the customer or the vendor belongs to a group, you can enter a group key here. The group key is freely assignable. + * + * If you create a matchcode using this group key, group evaluations are possible. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Group Key' + CustomerCorporateGroup : String(10); + /** Account number of another master record in which the official address is stored. This address is used, for example, for tax reports to the tax authorities in Italy. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Fiscal address' + @sap.quickinfo : 'Account number of the master record with the fiscal address' + FiscalAddress : String(10); + /** + * An industry is a distinct group of companies with the same basic business activity. The industry key is used in selecting data for evaluations (for example, a vendor master data list). You can specify industries such as trade, banking, service, manufacturing, health care, public service, media and so on. + * + * The industry field belongs to the general data area of customer and vendor master records. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Industry' + @sap.quickinfo : 'Industry key' + @sap.creatable : 'false' + @sap.updatable : 'false' + Industry : String(4); + /** + * Specifies the code that uniquely identifies the industry (or industries) of the customer. + * + * Depending on the standards your organization uses (for example, Standard Industry Codes (SIC)), enter the appropriate code. You can assign more than one industry code to a customer by choosing Create more. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Industry Code 1' + @sap.creatable : 'false' + @sap.updatable : 'false' + IndustryCode1 : String(10); + /** + * Specifies an additional code that identifies the industry (or industries) of the customer. + * + * Depending on the standards your organization uses (for example, Standard Industry Codes (SIC)), enter the appropriate code. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Industry Code 2' + @sap.creatable : 'false' + @sap.updatable : 'false' + IndustryCode2 : String(10); + /** + * Specifies an additional code that identifies the industry (or industries) of the customer. + * + * Depending on the standards your organization uses (for example, Standard Industry Codes (SIC)), enter the appropriate code. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Industry Code 3' + @sap.creatable : 'false' + @sap.updatable : 'false' + IndustryCode3 : String(10); + /** + * Specifies an additional code that identifies the industry (or industries) of the customer. + * + * Depending on the standards your organization uses (for example, Standard Industry Codes (SIC)), enter the appropriate code. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Industry Code 4' + @sap.creatable : 'false' + @sap.updatable : 'false' + IndustryCode4 : String(10); + /** + * Specifies an additional code that identifies the industry (or industries) of the customer. + * + * Depending on the standards your organization uses (for example, Standard Industry Codes (SIC)), enter the appropriate code. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Industry Code 5' + @sap.creatable : 'false' + @sap.updatable : 'false' + IndustryCode5 : String(10); + /** + * Here you enter the first 7 digits of the international location number. + * + * The International Location Number (ILN) is assigned (in Germany by the Centrale for Coorganisation GmbH)) when a company is founded. It consists of 13 digits, the last digit being the check digit. There are two categories of location numbers:Participants who only need an ILN to cleary and unmistakably identify themselves for communication with the business partner are given a category 1 ILN. This cannot be used to identify articles by means of EAN.Participants who wish to assign the location numbers for their own enterprise areas are given a category 2 ILN. For a category 2 ILN, digits 1 to 7 are described as basis number. This is used as basis for the creation of article numbers (EAN). + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Int. location no. 1' + @sap.quickinfo : 'International location number (part 1)' + InternationalLocationNumber1 : String(7); + /** + * Specifies a regional division according to the market categories created by the A. C. Nielsen company. + * + * By allocating a Nielsen division, you can use the services of the Nielsen Institute to create a market analysis of your customers. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Nielsen Indicator' + @sap.quickinfo : 'Nielsen ID' + NielsenRegion : String(2); + /** Classification of companies according to tax aspects. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax type' + ResponsibleType : String(2); + /** + * Specifies the tax number. + * + * Enter the appropriate tax number:Country Tax NumberArgentina CUIT number or CUIL numberBelgium Enterprise numberBrazil CNPJ numberBulgaria Unified identification codeChile RUT numberChina VAT registration number (shui wu deng ji hao)Colombia NIT numberCroatia Legal persons: company identification numberNatural persons: JMBG numberCzech Republic DIC numberFrance SIRET numberGreece Personal IDHungary Tax numberItaly Fiscal codeKazakhstan RNN (obsolete)Mexico RFC numberNetherlands SI registration number (Aansluitnummer UWV) of chain- liability vendorNorway VAT numberPeru RUC numberPhilippines Taxpayer identification number (see below)Poland NIP numberPortugal NIF numberRomania Tax numberRussia INNSlovakia DIC numberSlovenia Tax numberSouth Korea Natural persons: Personal identification numberLegal persons: Corporation IDSpain NIF numberSwitzerland UID numberTaiwan - China GUI registration numberThailand Personal IDTurkey Name of business partner's tax officeUkraine Taxpayer identification numberUnited Kingdom Company registration numberUnited States Social security numberVenezuela RIF numberIn the Philippines, enter the taxpayer identification number with a V or N at the end, as follows:If the business partner is liable to VAT: 999-999-999-999VIf the business partner is not liable to VAT: 999-999-999-999N + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number 1' + @sap.creatable : 'false' + @sap.updatable : 'false' + TaxNumber1 : String(16); + /** + * Specifies the tax number. + * + * Enter the appropriate tax number:Country Tax NumberArgentina NIP number or CM numberBelgium VAT numberBrazil CPF numberBulgaria Legal persons: tax numberNatural persons: personal IDCroatia OIB number Czech Republic ICO numberFrance SIREN numberGreece AFM numberIndia TINItaly VAT numberKazakhstan BC (Beneficiary Code)Netherlands BSN numberRussia OKPO codeSlovakia ICO numberSouth Korea VAT registration numberSweden Organization registration numberSwitzerland VAT numberTaiwan - China Tax registration numberUkraine Legal persons: USREOU numberNatural persons: SRNP numberTurkey Tax numberUnited Kingdom NI numberUnited States Employer identification numberVenezuela NIT number + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number 2' + @sap.creatable : 'false' + @sap.updatable : 'false' + TaxNumber2 : String(11); + /** + * Specifies the tax number. + * + * Enter the tax number that applies:Country Tax numberArgentina Withholding agent numberBrazil State tax numberBulgaria Social security numberMexico CURP numberKazakhstan BINNetherlands Tax registration number (Loonbelastingnummer) of the chain-liability vendorRussia KPP numberThailand Tax ID Ukraine VAT registration number + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number 3' + @sap.creatable : 'false' + @sap.updatable : 'false' + TaxNumber3 : String(18); + /** + * Specifies the tax number. + * + * Enter the appropriate tax number:Country Tax NumberBrazil Municipal tax numberKazakhstan IINRussia OFK number (for public bodies only) + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number 4' + @sap.creatable : 'false' + @sap.updatable : 'false' + TaxNumber4 : String(18); + /** + * Kazakhstan + * + * Specifies the certificate of registration as VAT payer in the following format: XXXXXYYYYYYYZZZZZZZZ, where: XXXXX is the certificate serial number, YYYYYYY is the certificate number and ZZZZZZZZ is the date of certificate issue. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number 5' + @sap.creatable : 'false' + @sap.updatable : 'false' + TaxNumber5 : String(60); + /** + * Taxes in Argentina: + * + * The format and the check of tax number 1 depend on the two-digit tax number type.The tax number type is an identification type for tax in Argentina (for example, 80 for CUIT) and is used for the DGI tax report. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number Type' + TaxNumberType : String(2); + /** + * VAT registration number (VAT reg.no.) of the customer, vendor or your company code. + * + * The VAT registration number is used within the EU for tax-exempt deliveries for the "EC sales list". The check rules are defined for each EU country and cannot be changed. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'VAT Registration No.' + @sap.quickinfo : 'VAT Registration Number' + VATRegistration : String(20); + /** + * Indicates that all data in this master record is to be deleted. + * + * To delete this data, you have to run the archiving program for Accounts Receivable or Payable. This program will archive all master records marked for deletion provided that there is no dependent data in them.Deletion flags can also be used in the program for deleting master data. You should, however, run this program only to delete test data prior to production startup. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Deletion flag' + @sap.quickinfo : 'Central Deletion Flag for Master Record' + DeletionIndicator : Boolean; + @cds.ambiguous : 'missing on condition?' + to_CustomerCompany : Association to many API_BUSINESS_PARTNER.A_CustomerCompany { }; + @cds.ambiguous : 'missing on condition?' + to_CustomerSalesArea : Association to many API_BUSINESS_PARTNER.A_CustomerSalesArea { }; +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Customer Company' +entity API_BUSINESS_PARTNER.A_CustomerCompany { + /** Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer' + @sap.quickinfo : 'Customer Number' + key Customer : String(10) not null; + /** The company code is an organizational unit within financial accounting. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Company Code' + key CompanyCode : String(4) not null; + /** Contains settings that control how the system handles differences between the invoice amount and the amount received from a customer or the amount paid to a supplier. A tolerance group is unique within a company code. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tolerance Group' + @sap.quickinfo : 'Tolerance Group for Business Partner/G/L Account' + APARToleranceGroup : String(4); + /** This field contains the account number the company is listed under at the customer. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account at customer' + @sap.quickinfo : 'Our account number at customer' + AccountByCustomer : String(12); + /** + * Identification code for the accounting clerk. + * + * The name of the accounting clerk defined by this identification code can be used in the payment program for correspondence and reporting (for example, open item lists). + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Clerk Abbrev.' + @sap.quickinfo : 'Accounting Clerk Abbreviation' + AccountingClerk : String(2); + @sap.label : 'Acctg clerk''s fax' + @sap.quickinfo : 'Accounting clerk''s fax number at the customer/vendor' + AccountingClerkFaxNumber : String(31); + @sap.label : 'Clrk''s internet add.' + @sap.quickinfo : 'Internet address of partner company clerk' + AccountingClerkInternetAddress : String(130); + @sap.display.format : 'UpperCase' + @sap.label : 'Acct.clerks tel.no.' + @sap.quickinfo : 'Accounting clerk''s telephone number at business partner' + AccountingClerkPhoneNumber : String(30); + /** + * + * + * Account number of the customer for whom automatic payment transactions are to be carried out.The account number is only needed if bank collections are not to be made via the customer who owes the receivables. The same applies to refunds of payables.The specification in this field only applies to this company code. There is another field in which you can enter an alternative payee for all company codes. If both fields are filled, the specification for the company code has priority. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Alternative payer' + @sap.quickinfo : 'Account number of an alternative payer' + AlternativePayerAccount : String(10); + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); + /** Indicator which specifies at what intervals the collective invoices are to be created for the customer. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Coll.Invoice Variant' + @sap.quickinfo : 'Collective Invoice Variant' + CollectiveInvoiceVariant : String(1); + /** + * Internal memo of the accounting department. + * + * The memo serves only as information on special features of the customer/vendor. + */ + @sap.label : 'Account Memo' + @sap.quickinfo : 'Memo' + CustomerAccountNote : String(30); + /** + * This field contains the account number of the head office. + * + * This account number is only specified for branch accounts. All postings for which the account number of the branch is specified, are automatically posted to the head office account. The account number of the branch affected is noted in the line items.No line items or balances are managed in the branch account. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Head office' + @sap.quickinfo : 'Head office account number (in branch accounts)' + CustomerHeadOffice : String(10); + /** + * Indicates that during automatic payment transactions clearing is made with the corresponding vendor account, and that during manual clearing procedures, the items of that vendor account are also selected. + * + * To use this function in automatic payment transactions, you have toenter the vendor account number in the customer master record,enter the customer account number in the vendor master record, andselect the "Clearing with customer" indicator in the vendor master record.If you set this indicator, the system will also include items of the vendor account in customer dunning. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Clearing with vendor' + @sap.quickinfo : 'Indicator: Clearing between customer and vendor ?' + CustomerSupplierClearingIsUsed : Boolean; + /** All bank data is determined using this key. */ + @sap.display.format : 'UpperCase' + @sap.label : 'House Bank' + @sap.quickinfo : 'Short Key for a House Bank' + HouseBank : String(5); + /** Enter an interest calculation indicator here if the account is to be included in automatic interest calculation. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Interest indicator' + @sap.quickinfo : 'Interest calculation indicator' + InterestCalculationCode : String(2); + /** + * The date in this field displays the last time the interest calculation program processed this account. This is generally the upper limit of the last interest run. + * + * Generally, this date is automatically maintained by the program (batch input). A manual entry in this field should only be made if an error has occurred or when implementing the interest calculation. + */ + @sap.display.format : 'Date' + @sap.label : 'Last Key Date' + @sap.quickinfo : 'Key Date of Last Interest Calculation' + InterestCalculationDate : Date; + /** + * Indicates that payment transactions and dunning notices are created for the branch. + * + * Normally automatic payment transactions and dunning notices are created for the head office.NoteSelect this indicator only if this account is a head office account. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Local Processing' + @sap.quickinfo : 'Indicator: Local Processing?' + IsToBeLocallyProcessed : Boolean; + /** If this indicator is set, every customer/vendor open item is paid separately during automatic payment transactions. This means that open items are not grouped together for payment. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Individual Payment' + @sap.quickinfo : 'Indicator: Pay All Items Separately?' + ItemIsToBePaidSeparately : Boolean; + /** + * Indicates the layout rule for the Allocation field in the document line item. + * + * The system uses a standard sort sequence for displaying line items. Among other things, it sorts the items according to the content of the Allocation field. This field can be filled either manually or automatically (by the system) when a document line item is entered.For this purpose, the system requires rules that determine which information is to be taken from the document header or from the document line item and placed in the field. The rules can be stored in the master record of an account which enables you to determine the standard sort sequence on an account-specific basis.NoteField information from another document line item cannot be adopted into the field of a particular item. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Sort Key' + @sap.quickinfo : 'Key for Sorting According to Assignment Numbers' + LayoutSortingRule : String(3); + /** + * Block key (enqueue key) that is used to block an open item or an account to payment transactions. + * + * You can use the block key as described below.Automatic Payment TransactionsIn automatic payment transactions, the block takes effect when it is entered in the system as follows:In the master recordIn the documentIf you enter the block in the master record then all open items for this account are contained in the exception list.The following block keys have a special meaning in the master record:The block key * has the effect that all items of the account are skipped in automatic payment transactions.The block key + has the effect that all items are skipped in which a payment method was not entered explicitly.The block key A is always set automatically when a down payment is entered. Therefore, you must not delete the block key A or use it for other purposes.Whether a block key can be set or removed in payment proposal processing depends on the attribute Changeable in payment proposal of the block key.Manual PaymentsManual payments are only affected by a block key in the document if you set the attribute Blocked for manual payments in the block key.A block key that was set in the master record does not have any effect on manual payments. You can have the system issue a warning message in that case. To do so, you have to make system settings. Set up message 671 of work area F5 in message control accordingly. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Payment Block' + @sap.quickinfo : 'Block Key for Payment' + PaymentBlockingReason : String(1); + /** + * List of payment methods which may be used in automatic payment transactions with this customer/vendor if you do not specify a payment method in the item to be paid. + * + * If you do specify a particular payment method in the item to be paid, this specification has priority over the specifications in the master record. You may also specify payment methods in the item which are not listed in the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Payment Methods' + @sap.quickinfo : 'List of Respected Payment Methods' + PaymentMethodsList : String(10); + /** + * Key for defining payment terms composed of cash discount percentages and payment periods. + * + * It is used in sales orders, purchase orders, and invoices. Terms of payment provide information for:Cash managementDunning proceduresPayment transactionsData can be entered in the field for the terms of payment key in various ways as you enter a business transaction:In most business transactions, the system defaults the key specified in the master record of the customer/vendor in question.In some transactions (for example, credit memos), however, the system does not default the key from the master record. Despite this, you can use the key from the customer/vendor master record by entering "*" in the field.Regardless of whether or not a key is defaulted from the master record, you can manually enter a key during document entry at:item level in sales ordersheader level in purchase orders and invoicesMaster records have separate areas for Financial Accounting, Sales, and Purchasing. You can specify different terms of payment keys in each of these areas. When you then enter a business transaction, the application in question will use the key specified in its area of the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Terms of Payment' + @sap.quickinfo : 'Terms of Payment Key' + PaymentTerms : String(4); + /** This indicator specifies that the customer/vendor should be sent all payment advice information by EDI. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Pmnt advice by EDI' + @sap.quickinfo : 'Indicator: Send Payment Advices by EDI' + PaytAdviceIsSentbyEDI : Boolean; + /** + * Indicates that the account is blocked for posting in the specified company code. + * + * If you set this indicator, the system prevents users from posting items to this account and issues an error message to inform them that the account is blocked. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Co.code post.block' + @sap.quickinfo : 'Posting block for company code' + PhysicalInventoryBlockInd : Boolean; + /** + * The reconciliation account in G/L accounting is the account which is updated parallel to the subledger account for normal postings (for example, invoice or payment). + * + * For special postings (for example, down payment or bill of exchange), this account is replaced by another account (for example, 'down payments received' instead of 'receivables').The replacement takes place due to the special G/L indicator which you must specify for these types of postings. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Reconciliation Acct' + @sap.quickinfo : 'Reconciliation Account in General Ledger' + ReconciliationAccount : String(10); + /** + * Indicator that the payment history of the customer is to be recorded. + * + * The amount and number of payments are then recorded per calendar month, as well as the average days in arrears.Information about cash discount payments and net payments is recorded separately.The indicator should not be set for one-time accounts and accounts which are paid automatically (bank collection or bank bill in Germany, bill of exchange payment request in France).You can only carry out evaluation of the payment history, for example, with the report for customer evaluation with OI listing, if you have selected this field. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Record Pmnt History' + @sap.quickinfo : 'Indicator: Record Payment History ?' + RecordPaymentHistoryIndicator : Boolean; + /** Name or identification code of the accounting clerk at the customer. */ + @sap.label : 'User at customer' + UserAtCustomer : String(15); + /** + * Indicates that the company code data in this master record is to be deleted. + * + * To delete this data, you have to run the archiving program for Accounts Receivable or Payable. This program will archive all master records marked for deletion provided that there is no dependent data in them.This deletion flag cannot be used in the program that deletes master data. You should, however, run this program only to delete test data prior to production startup. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Co.cde deletion flag' + @sap.quickinfo : 'Deletion Flag for Master Record (Company Code Level)' + DeletionIndicator : Boolean; + /** + * In cash management, customers and vendors are allocated to planning groups by means of an entry made in the master record. + * + * You can define these planning groups in Customizing or the Implementation Guide (you will need to ensure that they are all the same length). In order to improve the liquidity forecast display for major customers and vendors, it can be advisable to enter their account number as the planning group.For the planning groups themselves a naming convention should be set up to improve liquidity forecasting. In the following examples, the customer planning groups begin with an "R" for receipts, and the vendor planning groups begin with an "E" for expenses.R1 Customers paying by bank collectionR2 Other domestic customersR3 Customers abroadR4 Affiliated company customersR5 High risk customersR6 Major customersR7 Rental incomeR8 Repayment of loans...E1 Domestic vendorsE2 Vendors abroadE3 Affiliated company vendorsE4 Major vendorsE5 Personnel costsE6 TaxesE7 Investments... + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Planning Group' + CashPlanningGroup : String(10); + /** With the key specified here, you can refer to known/negotiated leave. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Known/Negotiat.Leave' + @sap.quickinfo : 'Short Key for Known/Negotiated Leave' + KnownOrNegotiatedLeave : String(4); + /** The value adjustment key controls the way the open items are processed during individual value adjustment. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Value Adjustment' + @sap.quickinfo : 'Value Adjustment Key' + ValueAdjustmentKey : String(2); + /** + * The account group is a classifying feature within customer master records. The account group determines: + * + * in which number range the customer account number should be;whether the number is assigned by the user or by the system;which specifications are necessary or possible in the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account Group' + @sap.quickinfo : 'Customer Account Group' + CustomerAccountGroup : String(4); + @cds.ambiguous : 'missing on condition?' + to_CustomerDunning : Association to many API_BUSINESS_PARTNER.A_CustomerDunning { }; + @cds.ambiguous : 'missing on condition?' + to_WithHoldingTax : Association to many API_BUSINESS_PARTNER.A_CustomerWithHoldingTax { }; +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Customer Dunning' +entity API_BUSINESS_PARTNER.A_CustomerDunning { + /** Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer' + @sap.quickinfo : 'Customer Number' + key Customer : String(10) not null; + /** The company code is an organizational unit within financial accounting. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Company Code' + key CompanyCode : String(4) not null; + /** + * The dunning area represents an organizational entity that is responsible for dunning. The dunning areas represent a sub-structure of the company codes. + * + * If different responsibilities or different dunning procedures exist within a company code, you can set up corresponding dunning areas.All dunning notices are made separately according to dunning areas, and if necessary with different dunning procedures.The dunning area must be noted in the line items. As long as documents are copied from preliminary work areas (billing documents), the dunning area can be derived from details such as division or sales area, if necessary. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Dunning Area' + key DunningArea : String(2) not null; + /** Key which reflects the reason for a dunning block indicator. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Dunning Block' + DunningBlock : String(1); + /** + * Number that specifies how often an item or account has been dunned. + * + * The business partner has received the dunning level from the last dunning run.If you use dunning areas, it is the dunning level that the business partner received from the last dunning run in the dunning area assigned.The dunning program sets the dunning level automatically when the customer or vendor receives a dunning notice. + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Dunning Level' + DunningLevel : String(1); + /** This field contains the key for the dunning procedure to be used. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Dunning Procedure' + DunningProcedure : String(4); + /** + * Account number of the customer who is to be the recipient of the dunning letters. + * + * The account number is only needed if dunning letters are not sent to the customer who owes the receivables. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Dunning Recipient' + @sap.quickinfo : 'Account Number of the Dunning Recipient' + DunningRecipient : String(10); + /** Date on which the last dunning notice was made. */ + @sap.display.format : 'Date' + @sap.label : 'Last Dunned' + @sap.quickinfo : 'Date of Last Dunning Notice' + LastDunnedOn : Date; + /** + * Date on which a legal dunning procedure was initiated. + * + * The printing of dunning notices in the legal dunning procedure generates an internal notice about any further account movements. A dunning notice is not created for the customer.If the Legal dunning procedure field in the master record contains a date, this means that the account is involved in a legal dunning procedure. The relationship between this date and the dunning date does not affect how the account is processed.The printing of account movements in the legal dunning procedure differs from the normal printing of dunning notices as follows:You must specify a separate form for your dunning procedure in Customizing. For more information, see Customizing (IMG) under Dunning Forms.The dunning program also displays text element 520 "Legal dunning procedure". This makes it possible to display the date of the legal dunning procedure from the master record.The program also displays the documents blocked for dunning and those with a payment method (automatic debit, bank direct debit).Although dunning notices are printed, the dunning level does not change in the master record or in the items. New dunning level = old dunning level.The program only updates the date of the last dunning run.Enter the date manually. + */ + @sap.display.format : 'Date' + @sap.label : 'Legal Dunn.Proc.From' + @sap.quickinfo : 'Date of the Legal Dunning Proceedings' + LegDunningProcedureOn : Date; + /** + * Identification code for the accounting clerk dealing with dunning letters. + * + * Using this identification code, the accounting clerk whose name is printed on the dunning letters is determined.If this field is not filled, then the entry from the Accounting clerk field is used. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Dunning Clerk' + DunningClerk : String(2); + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); + /** + * The account group is a classifying feature within customer master records. The account group determines: + * + * in which number range the customer account number should be;whether the number is assigned by the user or by the system;which specifications are necessary or possible in the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account Group' + @sap.quickinfo : 'Customer Account Group' + CustomerAccountGroup : String(4); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Sales Area' +entity API_BUSINESS_PARTNER.A_CustomerSalesArea { + /** Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer' + @sap.quickinfo : 'Customer Number' + key Customer : String(10) not null; + /** + * An organizational unit responsible for the sale of certain products or services. The responsibility of a sales organization may include legal liability for products and customer claims. + * + * You can assign any number of distribution channels and divisions to a sales organization. A particular combination of sales organization, distribution channel, and division is known as a sales area. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Sales Organization' + key SalesOrganization : String(4) not null; + /** + * The way in which products or services reach the customer. Typical examples of distribution channels are wholesale, retail, or direct sales. + * + * You can maintain information about customers and materials by sales organization and distribution channel. Within a sales organization you can deliver goods to a given customer through more than one distribution channel.You can assign a distribution channel to one or more sales organizations. If, for example, you have numerous sales organizations, each sales organization may use the "Wholesale" distribution channel.For each combination of sales organization and distribution channel, you can further assign one or more of the divisions that are defined for the sales organization. You can, for example, assign "Food" and "Non-food" divisions to the "Wholesale" distribution channel. A particular combination of sales organization, distribution channel, and division is known as a sales area. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Distribution Channel' + key DistributionChannel : String(2) not null; + /** + * A way of grouping materials, products, or services. The system uses divisions to determine the sales areas and the business areas for a material, product, or service. + * + * A product or service is always assigned to just one division. From the point of view of sales and distribution, the use of divisions lets you organize your sales structure around groups of similar products or product lines. This allows the people in a division who process orders and service customers to specialize within a manageable area of expertise.If a sales organization sells food and non-food products through both retail and wholesaledistribution channels each distribution channel could then be further split into food and non-food divisions. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Division' + key Division : String(2) not null; + /** This field contains the account number your company is listed under at the customer or vendor. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account at customer' + @sap.quickinfo : 'Shipper''s (Our) Account Number at the Customer or Vendor' + AccountByCustomer : String(12); + /** + * The authorization group enables you protect access to certain objects. + * + * In order to carry out a specific activity, the user must have authorization for the combination of the activity and the authorization group. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization Group' + AuthorizationGroup : String(4); + /** + * Indicates if further billing activities are blocked for the customer. The block applies throughout the specified sales area. + * + * If you enter a blocking indicator, billing that is already underway is continued. However, you cannot process the document further.Enter one of the values predefined for your system. If you want to block billing for a customer throughout an entire sales organization, you must enter a blocking indicator for each sales area in which the sales organization is defined.You can block billing for a customer if, for example, there are credit-related or legal problems to be resolved. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'BBlock for SlsA' + @sap.quickinfo : 'Billing block for customer (sales and distribution)' + BillingIsBlockedForCustomer : String(2); + /** Indicates whether a sales order must be delivered completely in a single delivery or whether the order can be partially delivered and completed over a number of deliveries. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Complete Delivery' + @sap.quickinfo : 'Complete Delivery Defined for Each Sales Order?' + CompleteDeliveryIsDefined : Boolean; + /** Customer's currency for a sales area. This currency will be used to settle the customer's charges for the given sales organization. */ + @sap.label : 'Currency' + @sap.semantics : 'currency-code' + Currency : String(5); + @sap.display.format : 'UpperCase' + @sap.label : 'ABC classification' + @sap.quickinfo : 'Customer classification (ABC analysis)' + CustomerABCClassification : String(2); + /** + * The account assignment group to which the system automatically posts the sales document. + * + * The system uses the account assignment group as one of the criteria during the automatic determination of revenue accounts.The system automatically proposes the account assignment group from the customer master record of the payer. You can change the default value in the sales document or the billing document. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Acct Assmt Grp Cust.' + @sap.quickinfo : 'Account Assignment Group for this customer' + CustomerAccountAssignmentGroup : String(2); + /** Identifies a particular group of customers (for example, wholesale or retail) for the purpose of pricing or generating statistics. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer Group' + CustomerGroup : String(2); + /** + * Key for defining payment terms composed of cash discount percentages and payment periods. + * + * It is used in sales orders, purchase orders, and invoices. Terms of payment provide information for:Cash managementDunning proceduresPayment transactionsData can be entered in the field for the terms of payment key in various ways as you enter a business transaction:In most business transactions, the system defaults the key specified in the master record of the customer/vendor in question.In some transactions (for example, credit memos), however, the system does not default the key from the master record. Despite this, you can use the key from the customer/vendor master record by entering "*" in the field.Regardless of whether or not a key is defaulted from the master record, you can manually enter a key during document entry at:item level in sales ordersheader level in purchase orders and invoicesMaster records have separate areas for Financial Accounting, Sales, and Purchasing. You can specify different terms of payment keys in each of these areas. When you then enter a business transaction, the application in question will use the key specified in its area of the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Terms of Payment' + @sap.quickinfo : 'Terms of Payment Key' + CustomerPaymentTerms : String(4); + /** + * A grouping of customers who share the same pricing requirements. + * + * You can define price groups according to the needs of your organization and create pricing records for each group. You can, for example, define a group of customers to whom you want to give the same kind of discount. You can assign a price group to an individual customer either in the customer master record or in the sales document.The system can propose the price group from the customer master record. You can change the proposed value manually in the sales document at both header and item level. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer Price Group' + CustomerPriceGroup : String(2); + /** + * Determines which pricing procedure the system should apply when you create a sales document for the customer. + * + * You can define different pricing procedures for your system. A pricing procedure determines the type and sequence of conditions that the system uses for pricing in, for example, a sales order. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Cust.Pric.Procedure' + @sap.quickinfo : 'Customer Classification for Pricing Procedure Determination' + CustomerPricingProcedure : String(2); + /** + * Indicates if further delivery processing is blocked for the customer. The block applies throughout the specified sales area. + * + * If you enter a blocking indicator, delivery processing that is already underway is continued. However, no new processing can take place.Enter one of the values predefined for your system. If you want to block delivery processing for a customer within a particular sales organization, you must enter a blocking indicator for each sales area in which the sales organization is defined.You can block delivery processing for a customer if, for example, there are credit-related or legal problems to be resolved. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'DelBlckSalesAr.' + @sap.quickinfo : 'Customer delivery block (sales area)' + DeliveryIsBlockedForCustomer : String(2); + /** + * The delivery priority assigned to an item. + * + * You can assign delivery priority to either a particular material or to a combination of customer and material. When you process deliveries collectively, you can use delivery priority as one of the selection criteria. + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Delivery Priority' + DeliveryPriority : String(2); + /** + * Commonly used trading terms that comply with the standards established by the International Chamber of Commerce (ICC). + * + * Incoterms specify internationally recognized procedures that the shipper and the receiving party must follow for the shipping transaction to be completed successfully.If goods are shipped through a port of departure, the appropriate Incoterm might be: FOB ("Free On Board"). You can provide further details (for example, the name of the port) in the secondary Incoterm field: FOB Boston, for example. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Incoterms' + @sap.quickinfo : 'Incoterms (Part 1)' + IncotermsClassification : String(3); + /** + * Provides additional information for the Incoterms. This field is only available for C-Clauses (if customized appropriately). Note the following for the incoterms versions below: + * + * No Version:This field is disabledIncoterm Version 2000This field is disabled as part of standard delivery unless a customer decides to enable it by the way of Customizing for Sales and Distribution under Master Data -> Business Partners -> Customers -> Billing Document -> Incoterms -> Map Incoterms to Versions.Incoterm Version 2010For this version, the field represents:Sea and inland waterway transport - Port of DestinationAny mode of transport - Place of Destination2010 Incoterms are divided as follows:Group 1: Rules for any mode or modes of transport (including by vessel)Incoterms Incoterms Description Location 2CPT Carriage Paid To Place of DestinationCIP Carriage & Insurance Paid To Place of DestinationGroup 2: Rules for sea and inland waterwaysIncoterms Incoterms Description Location 2CFR Cost & Freight Port of DestinationCIF Cost Insurance & Freight Port of Destination + */ + @sap.label : 'Incoterms Location 2' + IncotermsLocation2 : String(70); + /** An incoterms version is an edition containing a list of international terms for transportation that is defined by the International Chamber of Commerce (ICC). */ + @sap.display.format : 'UpperCase' + @sap.label : 'Incoterms Version' + IncotermsVersion : String(4); + /** + * Provides additional information for the primary Incoterm. For Incoterms 2010, this field represents: + * + * 1. For sea and inland waterway transport - Port of Shipment2. For any mode of transport - Place of Delivery 2010Incoterms are divided as follows:Group 1: Rules for any mode or modes of transport (including by vessel)Incoterms Incoterms Description Location 1 EXW Ex Works Place of DeliveryFCA Free Carrier Place of DeliveryCPT Carriage Paid To Place of DestinationCIP Carriage & Insurance Paid To Place of DestinationDAF Delivered at Frontier Place of DeliveryDDP Delivered Duty Paid Place of DestinationDDU Delivered Duty Unpaid Place of DestinationGroup 2: Rules for sea and inland waterwaysIncoterms Incoterms Description Location 1 FAS Free Alongside Ship Port of ShipmentFOB Free On Board Port of ShipmentCFR Cost & Freight Port of DestinationCIF Cost Insurance & Freight Port of DestinationDEQ Delivered Eq Quay (Duty Paid) Port of DestinationDES Delivered Ex Ship Port of DestinationIf the primary incoterm is specified as FOB “Free on Board”, the second field provides details of the port from which the delivery leaves, such as FOB Boston. + */ + @sap.label : 'Incoterms Location 1' + IncotermsLocation1 : String(70); + /** Indicates that all data in the master record will be deleted for the specified sales area. Before the deletion is made, the system checks for dependent data that would prevent the deletion. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Del.ID SlsArea' + @sap.quickinfo : 'Deletion flag for customer (sales level)' + DeletionIndicator : Boolean; + /** + * Additional information for the primary Incoterm. + * + * If the primary Incoterm is, for example, FOB ("Free on Board"), then the second field provides details of the port from which the delivery leaves (for example, "FOB Boston"). + */ + @sap.label : 'Incoterms (Part 2)' + IncotermsTransferLocation : String(28); + /** + * Identifies the calendar that determines the schedule of billing dates for the customer. + * + * If, for example, a customer wants to consolidate the invoices you send out, you can predefine the billing schedule in a calendar in the system. During billing, the system automatically proposes the appropriate billing date from the calendar.The system proposes the billing schedule from the customer master record of the payer. You can change the value manually in the sales document. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Invoicing Dates' + @sap.quickinfo : 'Invoice Dates (Calendar Identification)' + InvoiceDate : String(2); + /** + * The probability (expressed as a percentage) of the customer confirming the inquiry or quotation item as part of a sales order. + * + * The system combines the probability factors from the sales document type and from the customer master record of the sold-to party.If probability is 80% for the sales document type and 50% in the customer master record, the system combines the two values. In this case, the system takes 50% of 80% and proposes 40% for the item.The system proposes the probability. You can change the value manually for the item.You can generate requirements from quotations. Accordingly, the probability of quotation items affects how requirements are passed on. For example, a quotation for 100 pieces and a probability of 50% will generate requirements for 50 pieces. + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Order Probability' + @sap.quickinfo : 'Order Probability of the Item' + ItemOrderProbabilityInPercent : String(3); + /** + * Indicates whether you are allowed to combine orders during delivery processing. + * + * The system proposes the indicator from the customer master record. You can change the value manually in the sales document at both header and item level. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Order Combination' + @sap.quickinfo : 'Order Combination Indicator' + OrderCombinationIsAllowed : Boolean; + /** + * Indicates if further sales order processing is blocked for the customer. The block applies throughout the specified sales area. + * + * You can define blocks according to the needs of your organization. If you enter a blocking indicator, sales order processing that is already underway is continued. However, no new processing can occur.Enter one of the values predefined for your system. If you want to block sales order processing for a customer within a particular sales organization, you must enter a blocking indicator for each sales area in which the sale organization is defined.You can block sales order processing for a customer if, for example, there are credit-related or legal problems to be resolved. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Ord.blk:sls ar.' + @sap.quickinfo : 'Customer order block (sales area)' + OrderIsBlockedForCustomer : String(2); + /** + * Specifies whether the customer requires full or partial delivery for the item. + * + * You use this field to control partial deliveries at the item level. If the customer allows partial delivery, you can choose from different partial delivery options. For example, you can specify whether the customer allows you to make one delivery attempt only on the requested delivery date or whether unlimited delivery attempts are possible.When partial delivery indicator 'D' is set, the order can never have status 'fully delivered'. You must complete each item by entering a reason for rejection. This could be applied to scheduling agreements, for example.You can enter a value in this field only if the customer allows partial deliveries for the entire sales document. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Partial Deliv./Item' + @sap.quickinfo : 'Partial Delivery at Item Level' + PartialDeliveryIsAllowed : String(1); + /** + * Identifies a price list or other condition type (for example, a surcharge or discount). + * + * You can define price list types according to the needs of your own organization. Price list types can be grouped according to:the kind of price list (for example, wholesale or retail)the currency in which the price appearsthe number of the price list typeYou can use price list types to apply conditions during pricing or to generate statistics.In the customer master record, enter one of the values predefined for your system. The system proposes the value automatically during sales order processing. You can change the value manually in the sales document header. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Price List Type' + PriceListType : String(2); + /** + * A group of sales people who are responsible for processing sales of certain products or services. + * + * By using sales groups you can designate different areas of responsibility within a sales office. When you generate sales statistics, you can use the sales group as one of the selection criteria.If sales office personnel service both retail and wholesale markets, you can assign a sales group to each market.You assign each salesperson to a sales group in his or her user master record. You assign each customer to a particular sales group in the customer's master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Sales Group' + SalesGroup : String(3); + /** + * A physical location (for example, a branch office) that has responsibility for the sale of certain products or services within a given geographical area. + * + * When you create sales statistics, you can use a sales office as one of the selection criteria. When you print out order confirmations, you can include the address of the sales office.You can assign each customer to a sales office in the customer master record.Within a sales office you can establish sales groups (for example, departments) with specific sales responsibilities. Each person who works in the sales office can be assigned to a sales group in his or her user master record. Each customer can also be assigned to a particular sales group in the customer master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Sales Office' + SalesOffice : String(4); + /** + * General shipping strategy for the delivery of goods from the vendor to the customer. + * + * You can define shipping conditions in your system which correspond to the requirements of your company. You can specify a shipping condition in the customer master and in the vendor master.Shipping point determination (outbound delivery):The loading group, the plant and the shipping condition determine the shipping point that will be proposed by the system.Route determination (outbound delivery):Apart from the country and the geographical region of the shipping point, the ship-to party and the transportation group, the shipping condition determines the route that the system proposes in the order for the delivery of the goods. In the delivery, the route proposal also takes the weight group into account.A particular customer always requires immediate delivery. You enter the appropriate shipping condition into the customer master record. This means that when you process orders for this customer, the system automatically proposes the express mail room as a shipping point and the quickest way to the airport as a route.If a shipping condition has been assigned to a sales document type in Customizing, this condition will be proposed by the system in the corresponding sales document. If there is no assignment, the system copies the relevant data from the corresponding customer master record of the sold-to party. You cannot change this value during delivery processing. The shipping condition will not be copied from the delivery into the shipment. The shipping condition is one of several criteria for selecting deliveries when you create a shipment. You can enter a shipping condition manually in the shipment where it only serves as a characteristic for grouping shipments. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Shipping Conditions' + ShippingCondition : String(2); + /** + * Plant from which the goods should be delivered to the customer. + * + * This plant is automatically copied into the sales order item as the default value.If there is no default value when you process the sales order item, enter a delivering plant.The value proposed in the item is eitherfrom the customer master record of the goods recipient, orfrom the material master recordThe system checks whether it can propose a value (and for your own plants, whether the material has been created in the plant). If the system can propose a value, the plant is copied to the sales order item where you can change it as required. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Delivering Plant' + @sap.quickinfo : 'Delivering Plant (Own or External)' + SupplyingPlant : String(4); + /** + * A geographical sales district or region. + * + * Each customer can be assigned to a sales district. You can use sales districts to apply pricing conditions. When you want to generate sales statistics, you can use sales districts as a selection criteria.The system can propose a value from the customer master record of the sold-to party. You can change the value manually in the document at the header or item level. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Sales District' + SalesDistrict : String(6); + /** + * Identifies the customer's factory calendar that is used during the processing of invoice lists. + * + * An invoice list is a list of invoices (single or collective) that you create for the customer either periodically or on predefined dates. The periods and dates are defined in the customer's factory calendar. Typically, the recipient of an invoice list takes on the responsibility for collecting payments from numerous individual customers and receives a factoring or del credere discount for the service.If you want to create invoice lists for the customer, you must enter an identifier for a predefined factory calendar. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Invoice List Sched.' + @sap.quickinfo : 'Invoice List Schedule (calendar identification)' + InvoiceListSchedule : String(2); + /** + * Key representing a type of exchange rate in the system. + * + * You enter the exchange rate type to store different exchange rates.You can use the exchange rate type to define a buying rate, selling rate, or average rate for translating foreign currency amounts. You can use the average rate for the currency translation, and the bank buying and selling rates for valuation of foreign currency amounts. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Exchange Rate Type' + ExchangeRateType : String(4); + /** + * Specifies a customer-defined group of customers. + * + * You can define up to five different groups of customers, according to the needs of your organization. You specify the groups in the customer master record under "Additional data". If you assign a particular customer to one or more groups, the system automatically displays the groups in the header data of corresponding sales orders.You can define customer groups in Tables TVV1 through TVV5 and assign them to specific languages in Tables TVV1T through TVV5T. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer Group 1' + @sap.quickinfo : 'Customer group 1' + AdditionalCustomerGroup1 : String(3); + /** + * Specifies a customer-defined group of customers. + * + * You can define up to five different groups of customers, according to the needs of your organization. You specify the groups in the customer master record under "Additional data". If you assign a particular customer to one or more groups, the system automatically displays the groups in the header data of corresponding sales orders.You can define customer groups in Tables TVV1 through TVV5 and assign them to specific languages in Tables TVV1T through TVV5T. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer Group 2' + @sap.quickinfo : 'Customer group 2' + AdditionalCustomerGroup2 : String(3); + /** + * Specifies a customer-defined group of customers. + * + * You can define up to five different groups of customers, according to the needs of your organization. You specify the groups in the customer master record under "Additional data". If you assign a particular customer to one or more groups, the system automatically displays the groups in the header data of corresponding sales orders.You can define customer groups in Tables TVV1 through TVV5 and assign them to specific languages in Tables TVV1T through TVV5T. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer Group 3' + @sap.quickinfo : 'Customer group 3' + AdditionalCustomerGroup3 : String(3); + /** + * Specifies a customer-defined group of customers. + * + * You can define up to five different groups of customers, according to the needs of your organization. You specify the groups in the customer master record under "Additional data". If you assign a particular customer to one or more groups, the system automatically displays the groups in the header data of corresponding sales orders.You can define customer groups in Tables TVV1 through TVV5 and assign them to specific languages in Tables TVV1T through TVV5T. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer Group 4' + @sap.quickinfo : 'Customer group 4' + AdditionalCustomerGroup4 : String(3); + /** + * Specifies a customer-defined group of customers. + * + * You can define up to five different groups of customers, according to the needs of your organization. You specify the groups in the customer master record under "Additional data". If you assign a particular customer to one or more groups, the system automatically displays the groups in the header data of corresponding sales orders.You can define customer groups in Tables TVV1 through TVV5 and assign them to specific languages in Tables TVV1T through TVV5T. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer Group 5' + @sap.quickinfo : 'Customer group 5' + AdditionalCustomerGroup5 : String(3); + /** + * This key identifies the customer payment guarantee procedure. + * + * The customer payment guarantee procedure determines which payment guarantee procedure the system automatically uses when you create a sales document for the customer.In receivables risk management, the system determines the payment guarantee procedure taking into account:the key for the document payment guarantee procedure in the header for the sales document type.the customer payment guarantee procedure key in the customer master.You can define different payment guarantee procedures for your system. The payment guarantee procedure defines the type and sequence of forms of payment guarantee that the system assigns to the sales document items. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Paymt guarant. proc.' + @sap.quickinfo : 'Customer payment guarantee procedure' + PaymentGuaranteeProcedure : String(4); + /** + * The account group is a classifying feature within customer master records. The account group determines: + * + * in which number range the customer account number should be;whether the number is assigned by the user or by the system;which specifications are necessary or possible in the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account Group' + @sap.quickinfo : 'Customer Account Group' + CustomerAccountGroup : String(4); + @cds.ambiguous : 'missing on condition?' + to_PartnerFunction : Association to many API_BUSINESS_PARTNER.A_CustSalesPartnerFunc { }; + @cds.ambiguous : 'missing on condition?' + to_SalesAreaTax : Association to many API_BUSINESS_PARTNER.A_CustomerSalesAreaTax { }; +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Sales Area Tax' +entity API_BUSINESS_PARTNER.A_CustomerSalesAreaTax { + /** Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer' + @sap.quickinfo : 'Customer Number' + key Customer : String(10) not null; + /** + * An organizational unit responsible for the sale of certain products or services. The responsibility of a sales organization may include legal liability for products and customer claims. + * + * You can assign any number of distribution channels and divisions to a sales organization. A particular combination of sales organization, distribution channel, and division is known as a sales area. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Sales Organization' + key SalesOrganization : String(4) not null; + /** + * Specifies a distribution channel that you want to use as a reference for customer and material master data for other distribution channels. + * + * You can specify one distribution channel as the source of customer and material master data for other distribution channels. You need then only to maintain the data in one place.Distrib.channel Ref.distrib.channel01 0102 0103 0104 04In this example, only distribution channels 01 and 04 have customer and material master data defined. Distribution channels 01, 02, and 03 share the master data that you defined for distribution channel 01. Distribution channel 04 has its own master data. When you create a sales order in distribution channel 03, the system checks the customer and material master data against the data defined for distribution channel 01. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'RefDistCh-Cust/Mat.' + @sap.quickinfo : 'Reference distrib.channel for cust.and material masters' + key DistributionChannel : String(2) not null; + /** + * A way of grouping materials, products, or services. The system uses divisions to determine the sales areas and the business areas for a material, product, or service. + * + * A product or service is always assigned to just one division. From the point of view of sales and distribution, the use of divisions lets you organize your sales structure around groups of similar products or product lines. This allows the people in a division who process orders and service customers to specialize within a manageable area of expertise.If a sales organization sells food and non-food products through both retail and wholesaledistribution channels each distribution channel could then be further split into food and non-food divisions. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Division' + key Division : String(2) not null; + /** + * Identifies the country in which the delivery originates. + * + * You can define the country key in a table. As a rule, it is a good idea to use the existing international standards for identifying vehicles from different countries (for example: USA = United States, I = Italy, and so on). The system uses the key tohelp determine the relevant taxes during pricingdetermine important country-specific standards (the length of postal codes and bank account numbers, for example) + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Country' + @sap.quickinfo : 'Departure country (country from which the goods are sent)' + key DepartureCountry : String(3) not null; + /** + * Identifies the condition that the system uses to automatically determine country-specific taxes during pricing. + * + * You can define one or more tax categories for each country. During sales order processing, the system applies the tax category according tothe geographical location of your delivering plant and the location of the customer receiving the goodstax classifications in the customer master record and the material master record.In the USA, for example, you can define tax categories for Federal Sales Tax and Federal Excise Tax. In the U.K., you can define a tax category for Value Added Tax (VAT). + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Category' + @sap.quickinfo : 'Tax category (sales tax, federal sales tax,...)' + key CustomerTaxCategory : String(4) not null; + /** + * Specifies the tax liability of the customer, based on the tax structure of the customer's country. + * + * You can use the tax classification to specify, for example, whether a customer is liable for sales taxes, such as VAT or state sales taxes.During sales order processing, the system copies the tax classification from the tax information stored in thecustomer master record of the payer, if the payer is different from the sold-to party and the sales tax identification number is maintained for the payer.ship to party, if the sales tax identification number of the ship-to party is maintained.sold-to party, if none of the criteria for the payer or the ship-to party are met.During pricing, the system calculates any relevant taxes by taking the following factors into account:The tax classification of the customer and the materialThe country keys of the customer and the delivering plant + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Classification' + @sap.quickinfo : 'Tax classification for customer' + CustomerTaxClassification : String(1); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Withholding Tax' +entity API_BUSINESS_PARTNER.A_CustomerWithHoldingTax { + /** Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer' + @sap.quickinfo : 'Customer Number' + key Customer : String(10) not null; + /** The company code is an organizational unit within financial accounting. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Company Code' + key CompanyCode : String(4) not null; + /** + * This indicator is used to classify the different types of withholding tax. + * + * Withholding tax types classify particular features of a withholding tax including:The time at which the withholding tax is postedThe basis on which the base amount is calculatedThe basis for accumulation (if applicable)Withholding tax types are to be distinguished from withholding tax codes, to which are allocated the withholding tax percentage rate example.Whether a withholding tax can be defined as an existing type by means of a new code, or if a new type needs to be defined will depend on the type of transaction (see below).Note that a business transaction can only be assigned one withholding tax code per withholding tax type. If the business transaction is subject to several withholding taxes simultaneously, these must be represented by different types.This is the case in Argentina for example, where up to four kinds of withholding tax per business transaction are possible. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Withholding Tax Type' + @sap.quickinfo : 'Indicator for Withholding Tax Type' + key WithholdingTaxType : String(2) not null; + /** + * One or more "withholding tax codes" are assigned to each withholding tax type. One of the things these codes determine is the various percentage rates for the withholding tax type. + * + * Note that when processing a business transaction, no more than one withholding tax code can be assigned per withholding tax type. If the business transaction is subject to more than one withholding taxes, these must be represented in the system by defining various withholding tax types. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'W/Tax Code' + @sap.quickinfo : 'Withholding Tax Code' + WithholdingTaxCode : String(2); + @sap.display.format : 'UpperCase' + @sap.label : 'WTax Agent' + @sap.quickinfo : 'Indicator: Withholding Tax Agent?' + WithholdingTaxAgent : Boolean; + /** + * Date from which: + * + * The company code is obligated to withhold tax for the given withholding tax type.This date must be entered in Customizing under the withholding tax information for the company code.The customer is obligated to withhold tax for the withholding tax type.This date must be defined in the customer master record. + */ + @sap.display.format : 'Date' + @sap.label : 'W/Tax Obligated Frm' + @sap.quickinfo : 'Obligated to Withhold Tax From' + ObligationDateBegin : Date; + /** + * Date to which: + * + * The company code is obligated to withhold tax for the withholding tax type.This date must be entered in Customizing under the withholding tax information for the company code.The customer is obigated to withhold tax for the withholding tax type. + */ + @sap.display.format : 'Date' + @sap.label : 'Oblig.to W/Tax Until' + @sap.quickinfo : 'Obligated to Withhold Tax Until' + ObligationDateEnd : Date; + /** + * This is a number issued by the tax authorities per withholding tax type. + * + * This number must be specified in Customizing either:(a) As part of the withholding tax information defined for the company code, or(b) As part of the withholding tax information defined in the customer or vendor master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'W/tax number' + @sap.quickinfo : 'Withholding tax identification number' + WithholdingTaxNumber : String(16); + /** + * Numbered assigned by the relevant authorities for exemption from withholding tax. + * + * This number must be entered in the system as follows:In the vendor master record in the case of vendorsFor customers, in Customizing under the settings for withholding tax information for the company code per withholding tax type. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Exemption Number' + @sap.quickinfo : 'Exemption Certificate Number' + WithholdingTaxCertificate : String(25); + /** + * Rate of exemption from withholding tax. + * + * Those persons/activities subject to withholding tax can be exempted from withholding tax up to the percentage rate you enter here. This exemption rate refers to the withholding tax amount itself and not to the whole amount liable to withholding tax (withholding tax base amount).The gross amount of an invoice is 100.00 and the withholding tax base amount is defined as gross. The withholding tax rate is 10% meaning that the withholding tax amount is 10.00. Given an exemption rate of 30%, the withholding tax amount is reduced to 7.00. + */ + @sap.label : 'Exemption Rate' + WithholdingTaxExmptPercent : Decimal(5, 2); + /** Date from which withholding tax exemption applies. */ + @sap.display.format : 'Date' + @sap.label : 'Exemption Start Date' + @sap.quickinfo : 'Date on Which Exemption Begins' + ExemptionDateBegin : Date; + /** Date on which withholding tax exemption expires. */ + @sap.display.format : 'Date' + @sap.label : 'Exemption End Date' + @sap.quickinfo : 'Date on Which Exemption Ends' + ExemptionDateEnd : Date; + /** + * Indicator used to classify different types of exemption from liability to a particular withholding tax. + * + * These indicators can be defined per withholding tax type in the vendor master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Exemption Reason' + @sap.quickinfo : 'Reason for Exemption' + ExemptionReason : String(2); + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Sales Partner Functions' +entity API_BUSINESS_PARTNER.A_CustSalesPartnerFunc { + /** Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer' + @sap.quickinfo : 'Customer Number' + key Customer : String(10) not null; + /** + * An organizational unit responsible for the sale of certain products or services. The responsibility of a sales organization may include legal liability for products and customer claims. + * + * You can assign any number of distribution channels and divisions to a sales organization. A particular combination of sales organization, distribution channel, and division is known as a sales area. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Sales Organization' + key SalesOrganization : String(4) not null; + /** + * The way in which products or services reach the customer. Typical examples of distribution channels are wholesale, retail, or direct sales. + * + * You can maintain information about customers and materials by sales organization and distribution channel. Within a sales organization you can deliver goods to a given customer through more than one distribution channel.You can assign a distribution channel to one or more sales organizations. If, for example, you have numerous sales organizations, each sales organization may use the "Wholesale" distribution channel.For each combination of sales organization and distribution channel, you can further assign one or more of the divisions that are defined for the sales organization. You can, for example, assign "Food" and "Non-food" divisions to the "Wholesale" distribution channel. A particular combination of sales organization, distribution channel, and division is known as a sales area. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Distribution Channel' + key DistributionChannel : String(2) not null; + /** + * A way of grouping materials, products, or services. The system uses divisions to determine the sales areas and the business areas for a material, product, or service. + * + * A product or service is always assigned to just one division. From the point of view of sales and distribution, the use of divisions lets you organize your sales structure around groups of similar products or product lines. This allows the people in a division who process orders and service customers to specialize within a manageable area of expertise.If a sales organization sells food and non-food products through both retail and wholesaledistribution channels each distribution channel could then be further split into food and non-food divisions. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Division' + key Division : String(2) not null; + /** + * The sequential number that the system applies when there is more than one partner for a particular partner function. + * + * When you create a sales order for a particular customer, there may be more than one ship-to party defined. The different ship-to parties are numbered sequentially. + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Partner counter' + key PartnerCounter : String(3) not null; + /** The abbreviated form of the name that identifies the partner function. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Partner Function' + key PartnerFunction : String(2) not null; + @sap.display.format : 'UpperCase' + @sap.label : 'Customer' + @sap.quickinfo : 'Customer number of business partner' + BPCustomerNumber : String(10); + /** + * Sold-to party number sent in by the customer in delivery schedules. + * + * The system uses this number to automatically determine the ship-to party. + */ + @sap.label : 'Partner Description' + @sap.quickinfo : 'Cust.-Specif. Descr. of Business Partner (Plant, Stor. Loc.)' + CustomerPartnerDescription : String(30); + /** + * Specifies a partner as the default for a particular partner function. + * + * When you enter more than one partner for a particular partner function (for example, you define three different ship-to parties), you can select one partner as the default. During sales or purchasing processing, if you have defined multiple partners for a partner function, the system prompts you to choose just one partner. The system presents the default partner as the first choice in the pop-up window. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Default Partner' + DefaultPartner : Boolean; + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.creatable : 'false' +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Supplier' +entity API_BUSINESS_PARTNER.A_Supplier { + /** Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Supplier' + @sap.quickinfo : 'Account Number of Supplier' + key Supplier : String(10) not null; + /** + * The account number of the vendor with whom automatic payment transactions are carried out. + * + * The field is only needed if payments are not to be made directly to the vendor to whom the payable is owed. The same applies to bank collections of receivables.The specification in this field applies to all company codes. There is a further field in which every company code can enter an alternative payee separately. If both fields are filled, the company code specification has priority. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Alternative Payee' + @sap.quickinfo : 'Account Number of the Alternative Payee' + AlternativePayeeAccountNumber : String(10); + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); + /** Name with which the user who entered the master record was logged on in the R/3 System. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Created by' + @sap.quickinfo : 'Name of Person who Created the Object' + @sap.creatable : 'false' + @sap.updatable : 'false' + CreatedByUser : String(12); + /** Date on which the master record, or the part of the master record being viewed, was created. */ + @sap.display.format : 'Date' + @sap.label : 'Created on' + @sap.quickinfo : 'Date on which the Record Was Created' + @sap.creatable : 'false' + @sap.updatable : 'false' + CreationDate : Date; + /** Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Customer' + @sap.quickinfo : 'Customer Number' + Customer : String(10); + @sap.display.format : 'UpperCase' + @sap.label : 'Payment block' + @sap.quickinfo : 'Payment Block' + PaymentIsBlockedForSupplier : Boolean; + /** + * Indicates that the account is blocked for posting for all company codes. + * + * If you set this indicator, the system prevents users from posting items to this account and issues an error message to inform them that the account is blocked. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Posting Block' + @sap.quickinfo : 'Central Posting Block' + PostingIsBlocked : Boolean; + /** Indicates whether or not the supplier master record is blocked for all departments (that is, whether or not posting to this record is allowed at all). */ + @sap.display.format : 'UpperCase' + @sap.label : 'Purch. block' + @sap.quickinfo : 'Centrally imposed purchasing block' + PurchasingIsBlocked : Boolean; + /** + * The account group is a classifying feature within vendor master records. The account group determines: + * + * the number interval for the account number of the vendor,whether the number is assigned by the user or by the system,which specifications are necessary and/or possible in the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account Group' + @sap.quickinfo : 'Supplier Account Group' + SupplierAccountGroup : String(4); + @sap.display.format : 'UpperCase' + @sap.label : 'Supplier Name' + @sap.quickinfo : 'Supplier Full Name' + @sap.creatable : 'false' + @sap.updatable : 'false' + SupplierFullName : String(220); + @sap.label : 'Name of Supplier' + @sap.creatable : 'false' + @sap.updatable : 'false' + SupplierName : String(80); + /** + * VAT registration number (VAT reg.no.) of the customer, vendor or your company code. + * + * The VAT registration number is used within the EU for tax-exempt deliveries for the "EC sales list". The check rules are defined for each EU country and cannot be changed. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'VAT Registration No.' + @sap.quickinfo : 'VAT Registration Number' + VATRegistration : String(20); + @sap.display.format : 'Date' + @sap.label : 'Date of Birth' + @sap.quickinfo : 'Date of Birth of the Person Subject to Withholding Tax' + BirthDate : Date; + @sap.label : 'Int. Location No.' + @sap.quickinfo : 'Cocatenated International Location Number' + @sap.creatable : 'false' + @sap.updatable : 'false' + ConcatenatedInternationalLocNo : String(20); + /** + * Indicates that all data in this master record is to be deleted. + * + * To delete this data, you have to run the archiving program for Accounts Receivable or Payable. This program will archive all master records marked for deletion provided that there is no dependent data in them.Deletion flags can also be used in the program for deleting master data. You should, however, run this program only to delete test data prior to production startup. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Deletion flag' + @sap.quickinfo : 'Central Deletion Flag for Master Record' + DeletionIndicator : Boolean; + /** + * Specifies an additional master record in which the official address is stored. + * + * This address is used in Italy for business transactions with the tax office in Italy. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Fiscal address' + @sap.quickinfo : 'Account number of the master record with fiscal address' + FiscalAddress : String(10); + /** + * An industry is a distinct group of companies with the same basic business activity. The industry key is used in selecting data for evaluations (for example, a vendor master data list). You can specify industries such as trade, banking, service, manufacturing, health care, public service, media and so on. + * + * The industry field belongs to the general data area of customer and vendor master records. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Industry' + @sap.quickinfo : 'Industry key' + @sap.creatable : 'false' + @sap.updatable : 'false' + Industry : String(4); + /** + * Here you enter the first 7 digits of the international location number. + * + * The International Location Number (ILN) is assigned (in Germany by the Centrale for Coorganisation GmbH)) when a company is founded. It consists of 13 digits, the last digit being the check digit. There are two categories of location numbers:Participants who only need an ILN to cleary and unmistakably identify themselves for communication with the business partner are given a category 1 ILN. This cannot be used to identify articles by means of EAN.Participants who wish to assign the location numbers for their own enterprise areas are given a category 2 ILN. For a category 2 ILN, digits 1 to 7 are described as basis number. This is used as basis for the creation of article numbers (EAN). + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Int. location no. 1' + @sap.quickinfo : 'International location number (part 1)' + InternationalLocationNumber1 : String(7); + /** + * Here, you enter digits 8-12 of the 13-digit international location number. + * + * The international location number (ILN) is assigned when establishing a company (by the "Zentrale für Coorganisation GmbH" in Germany). It consists of 13 digits, the last of which is the check digit. There are two types of international location numbers:Subscribers who only need one ILN to identify themselves in communication with the business partner are given an ILN of type 1. These cannot be used for identifying articles by means of EAN.Subscribers who need to assign location numbers for their own company areas are given an ILN of type 2. Positions 1 through 7 of the ILN type 2 are known as the basis number. This basis number forms the basis for article numbers (EAN). + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Int. location no. 2' + @sap.quickinfo : 'International location number (Part 2)' + InternationalLocationNumber2 : String(5); + /** The check digit is derived from a special check digit procedure from digits of the previous international location numbers. In this way, you can check whether the ILN entered is actually valid. */ + @sap.display.format : 'NonNegative' + @sap.label : 'Check digit' + @sap.quickinfo : 'Check digit for the international location number' + InternationalLocationNumber3 : String(1); + /** + * Denotes a natural person. + * + * In the following countries, the system needs to know whether the taxpayer is a legal or natural person so that it can check the tax numbers correctly:BrazilBulgariaColombiaCroatiaGreeceItalyMexicoPeruSloveniaThailandUkraineThe flag is also used in conjunction with the Statement of Payments to Natural Persons report, as used in the Czech Republic and in Slovakia. This report only covers customers and vendors for whom you have set this indicator.In South Korea, it is used in conjunction with the Generic Withholding Tax Reporting program. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Natural Person' + IsNaturalPerson : String(1); + /** Classification of companies according to tax aspects. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax type' + ResponsibleType : String(2); + /** Date up to which the certification of the QM-system is valid. */ + @sap.display.format : 'Date' + @sap.label : 'QM System Valid To' + @sap.quickinfo : 'Validity date of certification' + SuplrQltyInProcmtCertfnValidTo : Date; + /** + * If a QM system is maintained by the supplier, you can store a description of the QM system here. + * + * If a material is activated for QM in procurement, the system initiates the following check whenever purchasing functions are carried out (for example, when a request for a quotation is made or if a purchase order is created):Whether the supplier's verified QM system, according to supplier master record or quality info-record (for a combination of supplier/material) meets the requirements for QM systems as specified in the material masterIn carrying out the check, the system relies on the defined assignments for target QM systems and actual QM systems in the Customizing application.If the check is unsuccessful, a warning message is issued when a request for quotation is initiated and an error message is issued for all other procurement activities. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Actual QM System' + @sap.quickinfo : 'Supplier''s QM system' + SuplrQualityManagementSystem : String(4); + /** + * If the customer or the vendor belongs to a group, you can enter a group key here. The group key is freely assignable. + * + * If you create a matchcode using this group key, group evaluations are possible. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Group Key' + SupplierCorporateGroup : String(10); + /** + * Key that determines which procurement functions (for example, request for quotation, purchase order, or goods receipt) should be blocked for quality reasons. + * + * You can enter a block key in the:Supplier master recordIn this case, the supplier block applies to all materials and plants.Quality info record for QM in procurementIn this case, the supplier block applies to a single material and plant.A block for quality reasons applies only to those materials for which QM in procurement is active. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Block Function' + @sap.quickinfo : 'Function That Will Be Blocked' + SupplierProcurementBlock : String(2); + /** + * Specifies the tax number. + * + * Enter the appropriate tax number:Country Tax NumberArgentina CUIT number or CUIL numberBelgium Enterprise numberBrazil CNPJ numberBulgaria Unified identification codeChile RUT numberChina VAT registration number (shui wu deng ji hao)Colombia NIT numberCroatia Legal persons: company identification numberNatural persons: JMBG numberCzech Republic DIC numberFrance SIRET numberGreece Personal IDHungary Tax numberItaly Fiscal codeKazakhstan RNN (obsolete)Mexico RFC numberNetherlands SI registration number (Aansluitnummer UWV) of chain- liability vendorNorway VAT numberPeru RUC numberPhilippines Taxpayer identification number (see below)Poland NIP numberPortugal NIF numberRomania Tax numberRussia INNSlovakia DIC numberSlovenia Tax numberSouth Korea Natural persons: Personal identification numberLegal persons: Corporation IDSpain NIF numberSwitzerland UID numberTaiwan - China GUI registration numberThailand Personal IDTurkey Name of business partner's tax officeUkraine Taxpayer identification numberUnited Kingdom Company registration numberUnited States Social security numberVenezuela RIF numberIn the Philippines, enter the taxpayer identification number with a V or N at the end, as follows:If the business partner is liable to VAT: 999-999-999-999VIf the business partner is not liable to VAT: 999-999-999-999N + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number 1' + @sap.creatable : 'false' + @sap.updatable : 'false' + TaxNumber1 : String(16); + /** + * Specifies the tax number. + * + * Enter the appropriate tax number:Country Tax NumberArgentina NIP number or CM numberBelgium VAT numberBrazil CPF numberBulgaria Legal persons: tax numberNatural persons: personal IDCroatia OIB number Czech Republic ICO numberFrance SIREN numberGreece AFM numberIndia TINItaly VAT numberKazakhstan BC (Beneficiary Code)Netherlands BSN numberRussia OKPO codeSlovakia ICO numberSouth Korea VAT registration numberSweden Organization registration numberSwitzerland VAT numberTaiwan - China Tax registration numberUkraine Legal persons: USREOU numberNatural persons: SRNP numberTurkey Tax numberUnited Kingdom NI numberUnited States Employer identification numberVenezuela NIT number + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number 2' + @sap.creatable : 'false' + @sap.updatable : 'false' + TaxNumber2 : String(11); + /** + * Specifies the tax number. + * + * Enter the tax number that applies:Country Tax numberArgentina Withholding agent numberBrazil State tax numberBulgaria Social security numberMexico CURP numberKazakhstan BINNetherlands Tax registration number (Loonbelastingnummer) of the chain-liability vendorRussia KPP numberThailand Tax ID Ukraine VAT registration number + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number 3' + @sap.creatable : 'false' + @sap.updatable : 'false' + TaxNumber3 : String(18); + /** + * Specifies the tax number. + * + * Enter the appropriate tax number:Country Tax NumberBrazil Municipal tax numberKazakhstan IINRussia OFK number (for public bodies only) + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number 4' + @sap.creatable : 'false' + @sap.updatable : 'false' + TaxNumber4 : String(18); + /** + * Kazakhstan + * + * Specifies the certificate of registration as VAT payer in the following format: XXXXXYYYYYYYZZZZZZZZ, where: XXXXX is the certificate serial number, YYYYYYY is the certificate number and ZZZZZZZZ is the date of certificate issue. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number 5' + @sap.creatable : 'false' + @sap.updatable : 'false' + TaxNumber5 : String(60); + /** The tax number of the vendor at the responsible tax authority. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number' + @sap.quickinfo : 'Tax Number at Responsible Tax Authority' + TaxNumberResponsible : String(18); + /** + * Taxes in Argentina: + * + * The format and the check of tax number 1 depend on the two-digit tax number type.The tax number type is an identification type for tax in Argentina (for example, 80 for CUIT) and is used for the DGI tax report. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax Number Type' + TaxNumberType : String(2); + /** + * This indicator controls the process of proof of delivery during the incoming goods process for inbound deliveries. Processing is activating by switching on this indicator in the supplier master and by switching on the corresponding indicator in the delivery item category. + * + * There are the following different characteristics:' ': not relevant for POD'A': generally relevant for POD'B': only relevant for POD if differences(Difference between notified quantity and actual quantity received) + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Relevant for POD' + @sap.quickinfo : 'Supplier indicator relevant for proof of delivery' + SuplrProofOfDelivRlvtCode : String(1); + /** + * Tax calculation for Brazil: + * + * The IPI tax value is split up for this vendor. 50% of the calculated IPI tax value is posted as deductible input tax, 50% is deducted from the inventory posting or posting to expense account. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tax split' + @sap.quickinfo : 'Tax Split' + BR_TaxIsSplit : Boolean; + @cds.ambiguous : 'missing on condition?' + to_SupplierCompany : Association to many API_BUSINESS_PARTNER.A_SupplierCompany { }; + @cds.ambiguous : 'missing on condition?' + to_SupplierPurchasingOrg : Association to many API_BUSINESS_PARTNER.A_SupplierPurchasingOrg { }; +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Supplier Company' +entity API_BUSINESS_PARTNER.A_SupplierCompany { + /** Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Supplier' + @sap.quickinfo : 'Account Number of Supplier' + key Supplier : String(10) not null; + /** The company code is an organizational unit within financial accounting. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Company Code' + key CompanyCode : String(4) not null; + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); + @sap.label : 'Company Name' + @sap.quickinfo : 'Name of Company Code or Company' + @sap.creatable : 'false' + @sap.updatable : 'false' + CompanyCodeName : String(25); + /** + * Block key (enqueue key) that is used to block an open item or an account to payment transactions. + * + * You can use the block key as described below.Automatic Payment TransactionsIn automatic payment transactions, the block takes effect when it is entered in the system as follows:In the master recordIn the documentIf you enter the block in the master record then all open items for this account are contained in the exception list.The following block keys have a special meaning in the master record:The block key * has the effect that all items of the account are skipped in automatic payment transactions.The block key + has the effect that all items are skipped in which a payment method was not entered explicitly.The block key A is always set automatically when a down payment is entered. Therefore, you must not delete the block key A or use it for other purposes.Whether a block key can be set or removed in payment proposal processing depends on the attribute Changeable in payment proposal of the block key.Manual PaymentsManual payments are only affected by a block key in the document if you set the attribute Blocked for manual payments in the block key.A block key that was set in the master record does not have any effect on manual payments. You can have the system issue a warning message in that case. To do so, you have to make system settings. Set up message 671 of work area F5 in message control accordingly. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Payment Block' + @sap.quickinfo : 'Block Key for Payment' + PaymentBlockingReason : String(1); + /** + * Indicates that the account is blocked for posting in the specified company code. + * + * If you set this indicator, the system prevents users from posting items to this account and issues an error message to inform them that the account is blocked. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Co.code post.block' + @sap.quickinfo : 'Posting block for company code' + SupplierIsBlockedForPosting : Boolean; + /** + * Identification code for the accounting clerk. + * + * The name of the accounting clerk defined by this identification code can be used in the payment program for correspondence and reporting (for example, open item lists). + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Clerk Abbrev.' + @sap.quickinfo : 'Accounting Clerk Abbreviation' + AccountingClerk : String(2); + @sap.label : 'Acctg clerk''s fax' + @sap.quickinfo : 'Accounting clerk''s fax number at the customer/vendor' + AccountingClerkFaxNumber : String(31); + @sap.display.format : 'UpperCase' + @sap.label : 'Acct.clerks tel.no.' + @sap.quickinfo : 'Accounting clerk''s telephone number at business partner' + AccountingClerkPhoneNumber : String(30); + /** Name or identification code of the accounting clerk at the vendor. */ + @sap.label : 'Clerk at vendor' + SupplierClerk : String(15); + @sap.label : 'Clrk''s internet add.' + @sap.quickinfo : 'Internet address of partner company clerk' + SupplierClerkURL : String(130); + /** + * List of payment methods which may be used in automatic payment transactions with this customer/vendor if you do not specify a payment method in the item to be paid. + * + * If you do specify a particular payment method in the item to be paid, this specification has priority over the specifications in the master record. You may also specify payment methods in the item which are not listed in the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Payment Methods' + @sap.quickinfo : 'List of Respected Payment Methods' + PaymentMethodsList : String(10); + /** + * Key for defining payment terms composed of cash discount percentages and payment periods. + * + * It is used in sales orders, purchase orders, and invoices. Terms of payment provide information for:Cash managementDunning proceduresPayment transactionsData can be entered in the field for the terms of payment key in various ways as you enter a business transaction:In most business transactions, the system defaults the key specified in the master record of the customer/vendor in question.In some transactions (for example, credit memos), however, the system does not default the key from the master record. Despite this, you can use the key from the customer/vendor master record by entering "*" in the field.Regardless of whether or not a key is defaulted from the master record, you can manually enter a key during document entry at:item level in sales ordersheader level in purchase orders and invoicesMaster records have separate areas for Financial Accounting, Sales, and Purchasing. You can specify different terms of payment keys in each of these areas. When you then enter a business transaction, the application in question will use the key specified in its area of the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Terms of Payment' + @sap.quickinfo : 'Terms of Payment Key' + PaymentTerms : String(4); + /** + * Indicates that during automatic payment transactions, clearing is made with the corresponding customer account, and that during manual clearing procedures, the items of that customer account are also selected. + * + * To use this function in automatic payment transactions, you have toenter the customer account number in the vendor master record,enter the vendor account number in the customer master record, andselect the "Clearing with vendor" indicator in the customer master record.If this indicator is set, items belonging to the customer account will be included in any dunning run. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Clearing with cust.' + @sap.quickinfo : 'Indicator: Clearing between customer and vendor?' + ClearCustomerSupplier : Boolean; + /** + * Indicates that payment transactions and dunning notices are created for the branch. + * + * Normally automatic payment transactions and dunning notices are created for the head office.NoteSelect this indicator only if this account is a head office account. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Local Processing' + @sap.quickinfo : 'Indicator: Local Processing?' + IsToBeLocallyProcessed : Boolean; + /** If this indicator is set, every customer/vendor open item is paid separately during automatic payment transactions. This means that open items are not grouped together for payment. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Individual Payment' + @sap.quickinfo : 'Indicator: Pay All Items Separately?' + ItemIsToBePaidSeparately : Boolean; + /** This indicator specifies that the customer/vendor should be sent all payment advice information by EDI. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Pmnt advice by EDI' + @sap.quickinfo : 'Indicator: Send Payment Advices by EDI' + PaymentIsToBeSentByEDI : Boolean; + /** All bank data is determined using this key. */ + @sap.display.format : 'UpperCase' + @sap.label : 'House Bank' + @sap.quickinfo : 'Short Key for a House Bank' + HouseBank : String(5); + /** + * Number of days which usually pass until the vendor has cashed your check. + * + * During automatic payment transactions, the system calculates the value date for check payments using this information and stores the date in the line item. The date is calculated as follows:Value date = posting date + check cashing timeIn Cash Management, the value date is used as information about the expected cash outflow. + */ + @sap.label : 'Check Cashing Time' + @sap.quickinfo : 'Probable Time Until Check Is Paid' + CheckPaidDurationInDays : Decimal(3, 0); + /** Currency key for amounts in the system. */ + @sap.label : 'Currency' + @sap.quickinfo : 'Currency Key' + @sap.semantics : 'currency-code' + Currency : String(5); + /** + * Maximum amount which may be issued on a bill of exchange if it is to be used in payment transactions with the business partner. + * + * The amount limit is taken into consideration in automatic payment transactions for payments by bill of exchange and bill of exchange payment requests. Several bill of exchange forms are created if the amount to be settled is higher than the maximum amount given here. Each of these bills of exchange is issued for the maximum amount or for a smaller amount.Amount limits for bills of exchange are used in Spain, for example. + */ + @sap.unit : 'Currency' + @sap.label : 'Bill/Ex. Limit' + @sap.quickinfo : 'Bill of Exchange Limit (in Local Currency)' + BillOfExchLmtAmtInCoCodeCrcy : Decimal(14, 3); + /** This field contains the account number the company is listed under at the vendor. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account with vendor' + @sap.quickinfo : 'Our account number with the vendor' + SupplierClerkIDBySupplier : String(12); + /** + * The reconciliation account in G/L accounting is the account which is updated parallel to the subledger account for normal postings (for example, invoice or payment). + * + * For special postings (for example, down payment or bill of exchange), this account is replaced by another account (for example, 'down payments received' instead of 'receivables').The replacement takes place due to the special G/L indicator which you must specify for these types of postings. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Reconciliation Acct' + @sap.quickinfo : 'Reconciliation Account in General Ledger' + ReconciliationAccount : String(10); + /** Enter an interest calculation indicator here if the account is to be included in automatic interest calculation. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Interest indicator' + @sap.quickinfo : 'Interest calculation indicator' + InterestCalculationCode : String(2); + /** + * The date in this field displays the last time the interest calculation program processed this account. This is generally the upper limit of the last interest run. + * + * Generally, this date is automatically maintained by the program (batch input). A manual entry in this field should only be made if an error has occurred or when implementing the interest calculation. + */ + @sap.display.format : 'Date' + @sap.label : 'Last Key Date' + @sap.quickinfo : 'Key Date of Last Interest Calculation' + InterestCalculationDate : Date; + /** + * This field contains the account number of the master record for the head office account. + * + * You specify this account number only for branch accounts. Items that you post using the branch account number are automatically posted to the head office account. The system records the branch account number in the line items.Neither transactions nor balances are kept in the branch account. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Head office' + @sap.quickinfo : 'Head office account number' + SupplierHeadOffice : String(10); + /** + * The account number of the vendor with whom automatic payment transactions are to be carried out. + * + * The field is only needed if payments are not to be made directly to the vendor to whom the payable is owed. The same applies to bank collections of receivables.The specification in this field applies only to the company code. There is a further field in which you can enter an alternative payee for each company code. If both fields are filled, the company code specified has priority. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Alternative payee' + @sap.quickinfo : 'Account number of the alternative payee' + AlternativePayee : String(10); + /** + * Indicates the layout rule for the Allocation field in the document line item. + * + * The system uses a standard sort sequence for displaying line items. Among other things, it sorts the items according to the content of the Allocation field. This field can be filled either manually or automatically (by the system) when a document line item is entered.For this purpose, the system requires rules that determine which information is to be taken from the document header or from the document line item and placed in the field. The rules can be stored in the master record of an account which enables you to determine the standard sort sequence on an account-specific basis.NoteField information from another document line item cannot be adopted into the field of a particular item. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Sort Key' + @sap.quickinfo : 'Key for Sorting According to Assignment Numbers' + LayoutSortingRule : String(3); + /** Contains settings that control how the system handles differences between the invoice amount and the amount received from a customer or the amount paid to a supplier. A tolerance group is unique within a company code. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Tolerance Group' + @sap.quickinfo : 'Tolerance Group for Business Partner/G/L Account' + APARToleranceGroup : String(4); + /** + * US government requirement. + * + * Date field in which to enter certification date for small companies run by women or minorities. This certificate must be renewed every two years. + */ + @sap.display.format : 'Date' + @sap.label : 'Certification Date' + SupplierCertificationDate : Date; + /** + * Internal memo of the accounting department. + * + * The memo serves only as information on special features of the customer/vendor. + */ + @sap.label : 'Account Memo' + @sap.quickinfo : 'Memo' + SupplierAccountNote : String(30); + /** + * In some countries, an additional country is needed for calculating or reporting withholding tax. + * + * The calculation can depend on the payee's country.A particular country key can be required by law for reporting which may possibly be different to the key used in the address.Examples: Japan, USA (1042), Argentina + */ + @sap.display.format : 'UpperCase' + @sap.label : 'WTax Country' + @sap.quickinfo : 'Withholding Tax Country Key' + WithholdingTaxCountry : String(3); + /** + * Indicates that the company code data in this master record is to be deleted. + * + * To delete this data, you have to run the archiving program for Accounts Receivable or Payable. This program will archive all master records marked for deletion provided that there is no dependent data in them.This deletion flag cannot be used in the program that deletes master data. You should, however, run this program only to delete test data prior to production startup. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Co.cde deletion flag' + @sap.quickinfo : 'Deletion Flag for Master Record (Company Code Level)' + DeletionIndicator : Boolean; + /** + * In cash management, customers and vendors are allocated to planning groups by means of an entry made in the master record. + * + * You can define these planning groups in Customizing or the Implementation Guide (you will need to ensure that they are all the same length). In order to improve the liquidity forecast display for major customers and vendors, it can be advisable to enter their account number as the planning group.For the planning groups themselves a naming convention should be set up to improve liquidity forecasting. In the following examples, the customer planning groups begin with an "R" for receipts, and the vendor planning groups begin with an "E" for expenses.R1 Customers paying by bank collectionR2 Other domestic customersR3 Customers abroadR4 Affiliated company customersR5 High risk customersR6 Major customersR7 Rental incomeR8 Repayment of loans...E1 Domestic vendorsE2 Vendors abroadE3 Affiliated company vendorsE4 Major vendorsE5 Personnel costsE6 TaxesE7 Investments... + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Planning Group' + CashPlanningGroup : String(10); + /** + * When incoming invoices are entered or when memos are entered in Financial Accounting (FI), the system checks whether an invoice or credit memo has already been entered for the same date. + * + * Checking Logistics DocumentsThe system checks whether the invoice documents have already been entered in the Logistics invoice verification. For this, the system checks invoices that have been held or parked or that contain errors, or invoices that were entered for invoice verification in the background. The check is performed only if you specify the reference document number when you enter the invoices.When checking for duplicate invoices, the system compares the following specified characteristics:VendorCurrencyCompany CodeGross Invoice AmountReference Document NumberInvoice Document DateIf all of these characteristics are the same, the system issues a message for which you can change the message type in Customizing.When you enter credit memos or subsequent adjustments, the system does not check for duplicate invoices.Exception: The exception is the Argentina country version, where the system checks for duplicate invoices and credit memos.No message is issued if you enter a document that has previously been reversed.In Customizing for Logistics Invoice Verification under Incoming Invoice -> Set Check for Duplicate Invoices, you can specify that the following characteristics are not checked:Reference Document NumberInvoice Document DateCompany CodeHaving fewer attributes to check increases the likelihood that the system will find a duplicate invoice.Example:The following document has already been entered and posted:Reference Document Number 333Invoice Date: 4/28/2000Gross Invoice Amount 100.00Currency: EURVendor: SpencerCompany Code: ChicagoYou have set up the check for duplicate invoices as follows in Customizing:The characteristics Reference Document Number and Company Code are not activated. Consequently, these characteristics are not checked.Now you enter the following invoice:Reference Document Number 334Invoice Date: 4/28/2000Gross Invoice Amount 100.00Currency: EURVendor: SpencerCompany Code: FlagstaffResultBecause you entered a reference document when you entered the invoice, the system checks for duplicate invoices. Compared against the invoice entered earlier, the invoice just entered has different values in the characteristics Reference and Company Code. However, these characteristics are not checked due to the settings that you have made in Customizing. All other characteristics are the same. The system issues a message telling you that an invoice has been entered twice.If the characteristic "Reference Document Number" had been selected in Customizing, the system would have checked the reference document number and established that it was different from the invoice entered earlier, and it consequently would not have issued a message.Checking FI DocumentsThe system checks whether there are FI documents that were posted or parked with the Logistics invoice verification or with an FI invoice transaction. Depending on the entry in the Reference field, one of the following checks is performed:If a reference number was specified in the sequential invoice/credit memo, the system checks whether an invoice/credit memo has already been posted for which all the following attributes agree:Company CodeVendorCurrencyDocument DateReference NumberIf no reference number was specified in the sequential invoice/credit memo, the system checks whether an invoice/credit memo has already been posted for which all the following attributes agree:Company CodeVendorCurrencyDocument DateAmount in Document CurrencyIn Materials Management, the system applies the check for duplicate invoices for invoices only, not for credit memos. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Check Double Invoice' + @sap.quickinfo : 'Check Flag for Double Invoices or Credit Memos' + IsToBeCheckedForDuplicates : Boolean; + @sap.display.format : 'UpperCase' + @sap.label : 'Minority Indicator' + MinorityGroup : String(3); + /** + * The account group is a classifying feature within vendor master records. The account group determines: + * + * the number interval for the account number of the vendor,whether the number is assigned by the user or by the system,which specifications are necessary and/or possible in the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account Group' + @sap.quickinfo : 'Supplier Account Group' + SupplierAccountGroup : String(4); + @cds.ambiguous : 'missing on condition?' + to_SupplierDunning : Association to many API_BUSINESS_PARTNER.A_SupplierDunning { }; + @cds.ambiguous : 'missing on condition?' + to_SupplierWithHoldingTax : Association to many API_BUSINESS_PARTNER.A_SupplierWithHoldingTax { }; +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Supplier Dunning' +entity API_BUSINESS_PARTNER.A_SupplierDunning { + /** Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Supplier' + @sap.quickinfo : 'Account Number of Supplier' + key Supplier : String(10) not null; + /** The company code is an organizational unit within financial accounting. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Company Code' + key CompanyCode : String(4) not null; + /** + * The dunning area represents an organizational entity that is responsible for dunning. The dunning areas represent a sub-structure of the company codes. + * + * If different responsibilities or different dunning procedures exist within a company code, you can set up corresponding dunning areas.All dunning notices are made separately according to dunning areas, and if necessary with different dunning procedures.The dunning area must be noted in the line items. As long as documents are copied from preliminary work areas (billing documents), the dunning area can be derived from details such as division or sales area, if necessary. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Dunning Area' + key DunningArea : String(2) not null; + /** Key which reflects the reason for a dunning block indicator. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Dunning Block' + DunningBlock : String(1); + /** + * Number that specifies how often an item or account has been dunned. + * + * The business partner has received the dunning level from the last dunning run.If you use dunning areas, it is the dunning level that the business partner received from the last dunning run in the dunning area assigned.The dunning program sets the dunning level automatically when the customer or vendor receives a dunning notice. + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Dunning Level' + DunningLevel : String(1); + /** This field contains the key for the dunning procedure to be used. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Dunning Procedure' + DunningProcedure : String(4); + /** + * Account number of the vendor who is to receive the dunning notice. + * + * Note:If an entry is not made in this field, the dunning notice is sent to the address of the vendor to be processed. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Dunn.recipient' + @sap.quickinfo : 'Account number of the dunning recipient' + DunningRecipient : String(10); + /** Date on which the last dunning notice was made. */ + @sap.display.format : 'Date' + @sap.label : 'Last Dunned' + @sap.quickinfo : 'Date of Last Dunning Notice' + LastDunnedOn : Date; + /** + * Date on which a legal dunning procedure was initiated. + * + * The printing of dunning notices in the legal dunning procedure generates an internal notice about any further account movements. A dunning notice is not created for the customer.If the Legal dunning procedure field in the master record contains a date, this means that the account is involved in a legal dunning procedure. The relationship between this date and the dunning date does not affect how the account is processed.The printing of account movements in the legal dunning procedure differs from the normal printing of dunning notices as follows:You must specify a separate form for your dunning procedure in Customizing. For more information, see Customizing (IMG) under Dunning Forms.The dunning program also displays text element 520 "Legal dunning procedure". This makes it possible to display the date of the legal dunning procedure from the master record.The program also displays the documents blocked for dunning and those with a payment method (automatic debit, bank direct debit).Although dunning notices are printed, the dunning level does not change in the master record or in the items. New dunning level = old dunning level.The program only updates the date of the last dunning run.Enter the date manually. + */ + @sap.display.format : 'Date' + @sap.label : 'Legal Dunn.Proc.From' + @sap.quickinfo : 'Date of the Legal Dunning Proceedings' + LegDunningProcedureOn : Date; + /** + * Identification code for the accounting clerk dealing with dunning letters. + * + * Using this identification code, the accounting clerk whose name is printed on the dunning letters is determined.If this field is not filled, then the entry from the Accounting clerk field is used. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Dunning Clerk' + DunningClerk : String(2); + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); + /** + * The account group is a classifying feature within vendor master records. The account group determines: + * + * the number interval for the account number of the vendor,whether the number is assigned by the user or by the system,which specifications are necessary and/or possible in the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account Group' + @sap.quickinfo : 'Supplier Account Group' + SupplierAccountGroup : String(4); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Purchasing Partner Functions' +entity API_BUSINESS_PARTNER.A_SupplierPartnerFunc { + /** Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Supplier' + @sap.quickinfo : 'Account Number of Supplier' + key Supplier : String(10) not null; + /** Denotes the purchasing organization. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Purch. Organization' + @sap.quickinfo : 'Purchasing Organization' + key PurchasingOrganization : String(4) not null; + /** + * Subdivision of a supplier's overall product range according to various criteria. + * + * For each supplier sub-range:The master data is kept on a common basisCertain conditions applyIn the supplier master, you can create different purchasing data and different partner functions for each supplier sub-range.You can also maintain and change the conditions for each supplier sub-range. You assign a material to a supplier sub-range in the info record.In the supplier master, you can maintain different data for particular supplier sub-ranges, such as ordering addresses or terms of payment, for example.When creating a purchase order with a known supplier, different data is only determined if the supplier sub-range is entered in the initial screen.Your supplier Smith in Houston has two sub-ranges: paint and glue.All materials from the "paint" sub-range are ordered in Houston.You have maintained an alternative ordering address in Detroit for the "glue" sub-range.If you order materials from the "glue" sub-range, the supplier sub-range finds the Detroit ordering address. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Supplier Subrange' + key SupplierSubrange : String(6) not null; + /** Key uniquely identifying a plant. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Plant' + key Plant : String(4) not null; + /** The abbreviated form of the name that identifies the partner function. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Partner Function' + key PartnerFunction : String(2) not null; + /** + * The sequential number that the system applies when there is more than one partner for a particular partner function. + * + * When you create a sales order for a particular customer, there may be more than one ship-to party defined. The different ship-to parties are numbered sequentially. + */ + @sap.display.format : 'NonNegative' + @sap.label : 'Partner counter' + key PartnerCounter : String(3) not null; + /** + * Specifies a partner as the default for a particular partner function. + * + * When you enter more than one partner for a particular partner function (for example, you define three different ship-to parties), you can select one partner as the default. During sales or purchasing processing, if you have defined multiple partners for a partner function, the system prompts you to choose just one partner. The system presents the default partner as the first choice in the pop-up window. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Default Partner' + DefaultPartner : Boolean; + @sap.display.format : 'Date' + @sap.label : 'Created On' + @sap.quickinfo : 'Date on Which Record Was Created' + @sap.creatable : 'false' + @sap.updatable : 'false' + CreationDate : Date; + @sap.display.format : 'UpperCase' + @sap.label : 'Created By' + @sap.quickinfo : 'Name of Person Who Created Object' + @sap.creatable : 'false' + @sap.updatable : 'false' + CreatedByUser : String(12); + @sap.display.format : 'UpperCase' + @sap.label : 'Ref. to vendor' + @sap.quickinfo : 'Reference to other vendor' + ReferenceSupplier : String(10); + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.deletable : 'false' +@sap.content.version : '1' +@sap.label : 'Purchasing Organization' +entity API_BUSINESS_PARTNER.A_SupplierPurchasingOrg { + /** + * Alphanumeric key uniquely identifying the document. + * + * With the supplier number, information from the supplier master record (such as the supplier's address and bank details) is copied into a purchasing document (such as a request for quotation or a purchase order).You can use the supplier number to keep track of requests for quotation, purchase orders and outline agreements. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Supplier' + @sap.quickinfo : 'Supplier''s Account Number' + key Supplier : String(10) not null; + /** Denotes the purchasing organization. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Purch. Organization' + @sap.quickinfo : 'Purchasing Organization' + key PurchasingOrganization : String(4) not null; + /** + * Determines which calculation schema (pricing procedure) is to be used in purchasing documents containing this supplier number. + * + * You can use the schema group to specify the calculation schema per purchasing organization or supplier. The relevant calculation schema is determined by reference to the schema group.The effect of this is that the conditions to be maintained in a purchasing document can differ depending on the relevant purchasing organization or supplier.If a calculation schema is only to be valid for certain purchasing organizations or suppliers, proceed as follows:Define the schema group for the purchasing organization or the supplier using the relevant function in the menu "Calculation schema -> Schema groups".Assign the schema group to the calculation schema via "Calculation schema -> Determine schema".Enter the schema group for the supplier in the supplier master records to which the calculation schema is to be assigned. Assign the schema group of the purchasing organization to the relevant purchasing organization using "Calculation schema -> Schema group -> Assign to purch. org.". + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Schema Grp, Supplier' + @sap.quickinfo : 'Group for Calculation Schema (Supplier)' + CalculationSchemaGroupCode : String(2); + /** Indicates whether or not the supplier master record is earmarked for deletion. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Del. flag POrg.' + @sap.quickinfo : 'Deletion Indicator for Supplier at Purchasing Level' + DeletionIndicator : Boolean; + /** + * Commonly used trading terms that comply with the standards established by the International Chamber of Commerce (ICC). + * + * Incoterms specify internationally recognized procedures that the shipper and the receiving party must follow for the shipping transaction to be completed successfully.If goods are shipped through a port of departure, the appropriate Incoterm might be: FOB ("Free On Board"). You can provide further details (for example, the name of the port) in the secondary Incoterm field: FOB Boston, for example. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Incoterms' + @sap.quickinfo : 'Incoterms (Part 1)' + IncotermsClassification : String(3); + /** + * Additional information for the primary Incoterm. + * + * If the primary Incoterm is, for example, FOB ("Free on Board"), then the second field provides details of the port from which the delivery leaves (for example, "FOB Boston"). + */ + @sap.label : 'Incoterms (Part 2)' + IncotermsTransferLocation : String(28); + /** An incoterms version is an edition containing a list of international terms for transportation that is defined by the International Chamber of Commerce (ICC). */ + @sap.display.format : 'UpperCase' + @sap.label : 'Incoterms Version' + IncotermsVersion : String(4); + /** + * Provides additional information for the primary Incoterm. For Incoterms 2010, this field represents: + * + * 1. For sea and inland waterway transport - Port of Shipment2. For any mode of transport - Place of Delivery 2010Incoterms are divided as follows:Group 1: Rules for any mode or modes of transport (including by vessel)Incoterms Incoterms Description Location 1 EXW Ex Works Place of DeliveryFCA Free Carrier Place of DeliveryCPT Carriage Paid To Place of DestinationCIP Carriage & Insurance Paid To Place of DestinationDAF Delivered at Frontier Place of DeliveryDDP Delivered Duty Paid Place of DestinationDDU Delivered Duty Unpaid Place of DestinationGroup 2: Rules for sea and inland waterwaysIncoterms Incoterms Description Location 1 FAS Free Alongside Ship Port of ShipmentFOB Free On Board Port of ShipmentCFR Cost & Freight Port of DestinationCIF Cost Insurance & Freight Port of DestinationDEQ Delivered Eq Quay (Duty Paid) Port of DestinationDES Delivered Ex Ship Port of DestinationIf the primary incoterm is specified as FOB “Free on Board”, the second field provides details of the port from which the delivery leaves, such as FOB Boston. + */ + @sap.label : 'Incoterms Location 1' + IncotermsLocation1 : String(70); + /** + * Provides additional information for the Incoterms. This field is only available for C-Clauses (if customized appropriately). Note the following for the incoterms versions below: + * + * No Version:This field is disabledIncoterm Version 2000This field is disabled as part of standard delivery unless a customer decides to enable it by the way of Customizing for Sales and Distribution under Master Data -> Business Partners -> Customers -> Billing Document -> Incoterms -> Map Incoterms to Versions.Incoterm Version 2010For this version, the field represents:Sea and inland waterway transport - Port of DestinationAny mode of transport - Place of Destination2010 Incoterms are divided as follows:Group 1: Rules for any mode or modes of transport (including by vessel)Incoterms Incoterms Description Location 2CPT Carriage Paid To Place of DestinationCIP Carriage & Insurance Paid To Place of DestinationGroup 2: Rules for sea and inland waterwaysIncoterms Incoterms Description Location 2CFR Cost & Freight Port of DestinationCIF Cost Insurance & Freight Port of Destination + */ + @sap.label : 'Incoterms Location 2' + IncotermsLocation2 : String(70); + /** Indicator specifying that provision has been made for goods-receipt-based invoice verification for a purchase order item or invoice item. */ + @sap.display.format : 'UpperCase' + @sap.label : 'GR-Based Inv. Verif.' + @sap.quickinfo : 'Indicator: GR-Based Invoice Verification' + InvoiceIsGoodsReceiptBased : Boolean; + /** + * Number of calendar days needed to obtain the material or service if it is procured externally. + * + * If you have different vendors for a material, you must specify an average value. The same applies if you order the material from a fixed vendor that has varying delivery times.If you use the SAP Retail System, the planned delivery time can be suggested from the vendor sub-range in the vendor master record. + */ + @sap.label : 'Planned Deliv. Time' + @sap.quickinfo : 'Planned Delivery Time in Days' + MaterialPlannedDeliveryDurn : Decimal(3, 0); + /** Minimum value specified for purchase orders issued to the relevant supplier. */ + @sap.unit : 'PurchaseOrderCurrency' + @sap.label : 'Minimum order value' + MinimumOrderAmount : Decimal(14, 3); + /** + * Key for defining payment terms composed of cash discount percentages and payment periods. + * + * It is used in sales orders, purchase orders, and invoices. Terms of payment provide information for:Cash managementDunning proceduresPayment transactionsData can be entered in the field for the terms of payment key in various ways as you enter a business transaction:In most business transactions, the system defaults the key specified in the master record of the customer/vendor in question.In some transactions (for example, credit memos), however, the system does not default the key from the master record. Despite this, you can use the key from the customer/vendor master record by entering "*" in the field.Regardless of whether or not a key is defaulted from the master record, you can manually enter a key during document entry at:item level in sales ordersheader level in purchase orders and invoicesMaster records have separate areas for Financial Accounting, Sales, and Purchasing. You can specify different terms of payment keys in each of these areas. When you then enter a business transaction, the application in question will use the key specified in its area of the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Terms of Payment' + @sap.quickinfo : 'Terms of Payment Key' + PaymentTerms : String(4); + /** + * Determines which date is to be used for price determination (pricing) purposes. + * + * Enter the key for the desired date.If you choose the date of goods receipt, for example, a new price will be determined upon the arrival of the goods, causing the item to be revaluated at this time.NoteIf you have chosen the delivery date as the date for price determination and an item contains several delivery dates (i.e. has a delivery schedule), the first delivery date (the delivery date specified in the first schedule line) is taken. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Pricing Date Control' + @sap.quickinfo : 'Price Determination (Pricing) Date Control' + PricingDateControl : String(1); + /** + * Allows you to automatically generate purchase orders from purchase requisitions if the requisition has been assigned to a supplier (source of supply). + * + * If you want to use automatic conversion, note the following additional conditions:In the case of purchase requisitions for materials, you should also select the indicator Autom.purch.ord. in the Purchasing view in the material master record.In the case of purchase requisitions for services, you should also select the indicator Automatic creation of POs for service PReqs in Customizing for Services by choosing:IMG -> MM -> External Services Management -> Source Determination and Default Values- for Client or- for Purchasing Organization + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Automatic PO' + @sap.quickinfo : 'Automatic Generation of Purchase Order Allowed' + PurOrdAutoGenerationIsAllowed : Boolean; + /** Key for the currency on which an order placed with a supplier is based. */ + @sap.label : 'Order currency' + @sap.quickinfo : 'Purchase order currency' + @sap.semantics : 'currency-code' + PurchaseOrderCurrency : String(5); + /** + * Key for a buyer or a group of buyers, who is/are responsible for certain purchasing activities. + * + * Internally, the purchasing group is responsible for the procurement of a material or a class of materials.Externally, it is the medium through which contacts with the vendor are maintained. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Purchasing Group' + PurchasingGroup : String(3); + /** Indicates whether or not the supplier master record is blocked for the purchasing organization for posting purposes. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Pur. block POrg' + @sap.quickinfo : 'Purchasing block at purchasing organization level' + PurchasingIsBlockedForSupplier : Boolean; + /** + * General shipping strategy for the delivery of goods from the vendor to the customer. + * + * You can define shipping conditions in your system which correspond to the requirements of your company. You can specify a shipping condition in the customer master and in the vendor master.Shipping point determination (outbound delivery):The loading group, the plant and the shipping condition determine the shipping point that will be proposed by the system.Route determination (outbound delivery):Apart from the country and the geographical region of the shipping point, the ship-to party and the transportation group, the shipping condition determines the route that the system proposes in the order for the delivery of the goods. In the delivery, the route proposal also takes the weight group into account.A particular customer always requires immediate delivery. You enter the appropriate shipping condition into the customer master record. This means that when you process orders for this customer, the system automatically proposes the express mail room as a shipping point and the quickest way to the airport as a route.If a shipping condition has been assigned to a sales document type in Customizing, this condition will be proposed by the system in the corresponding sales document. If there is no assignment, the system copies the relevant data from the corresponding customer master record of the sold-to party. You cannot change this value during delivery processing. The shipping condition will not be copied from the delivery into the shipment. The shipping condition is one of several criteria for selecting deliveries when you create a shipment. You can enter a shipping condition manually in the shipment where it only serves as a characteristic for grouping shipments. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Shipping Conditions' + ShippingCondition : String(2); + /** + * Means of classifying suppliers according to their significance to your company. + * + * The indicator serves to assign the supplier to one of the categories A, B or C, in accordance with ABC analysis.'A' category suppliers, for instance, are those accounting for the greatest share of the company's total annual spend (in value terms). + */ + @sap.display.format : 'UpperCase' + @sap.label : 'ABC indicator' + SupplierABCClassificationCode : String(1); + /** This telephone number is maintained in the supplier master record and adopted in the purchasing document. */ + @sap.label : 'Telephone' + @sap.quickinfo : 'Supplier''s Telephone Number' + SupplierPhoneNumber : String(16); + @sap.label : 'Salesperson' + @sap.quickinfo : 'Responsible Salesperson at Supplier''s Office' + SupplierRespSalesPersonName : String(30); + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); + /** + * The account group is a classifying feature within vendor master records. The account group determines: + * + * the number interval for the account number of the vendor,whether the number is assigned by the user or by the system,which specifications are necessary and/or possible in the master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Account Group' + @sap.quickinfo : 'Supplier Account Group' + SupplierAccountGroup : String(4); + @cds.ambiguous : 'missing on condition?' + to_PartnerFunction : Association to many API_BUSINESS_PARTNER.A_SupplierPartnerFunc { }; +}; + +@cds.external : true +@cds.persistence.skip : true +@sap.content.version : '1' +@sap.label : 'Company Withholding Tax' +entity API_BUSINESS_PARTNER.A_SupplierWithHoldingTax { + /** Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Supplier' + @sap.quickinfo : 'Account Number of Supplier' + key Supplier : String(10) not null; + /** The company code is an organizational unit within financial accounting. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Company Code' + key CompanyCode : String(4) not null; + /** + * This indicator is used to classify the different types of withholding tax. + * + * Withholding tax types classify particular features of a withholding tax including:The time at which the withholding tax is postedThe basis on which the base amount is calculatedThe basis for accumulation (if applicable)Withholding tax types are to be distinguished from withholding tax codes, to which are allocated the withholding tax percentage rate example.Whether a withholding tax can be defined as an existing type by means of a new code, or if a new type needs to be defined will depend on the type of transaction (see below).Note that a business transaction can only be assigned one withholding tax code per withholding tax type. If the business transaction is subject to several withholding taxes simultaneously, these must be represented by different types.This is the case in Argentina for example, where up to four kinds of withholding tax per business transaction are possible. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Withholding Tax Type' + @sap.quickinfo : 'Indicator for Withholding Tax Type' + key WithholdingTaxType : String(2) not null; + /** Date from which withholding tax exemption applies. */ + @sap.display.format : 'Date' + @sap.label : 'Exemption Start Date' + @sap.quickinfo : 'Date on Which Exemption Begins' + ExemptionDateBegin : Date; + /** Date on which withholding tax exemption expires. */ + @sap.display.format : 'Date' + @sap.label : 'Exemption End Date' + @sap.quickinfo : 'Date on Which Exemption Ends' + ExemptionDateEnd : Date; + /** + * Indicator used to classify different types of exemption from liability to a particular withholding tax. + * + * These indicators can be defined per withholding tax type in the vendor master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Exemption Reason' + @sap.quickinfo : 'Reason for Exemption' + ExemptionReason : String(2); + @sap.display.format : 'UpperCase' + @sap.label : 'Subject to W/Tx' + @sap.quickinfo : 'Indicator: Subject to Withholding Tax?' + IsWithholdingTaxSubject : Boolean; + /** + * The type of recipient can be defined in the vendor master record. + * + * It is used to group vendors together according to particular characteristics such as occupations that may be subject to the same withholding tax type, but which are required to pay different percentage rates (as defined by the withholding tax code).Application in ThailandThis corresponds to the official Thai form number (Phaw.Ngor.Daw) and is used to determine the sequential numbering of a withholding tax certificate. The form number is defined in the vendor master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Recipient Type' + @sap.quickinfo : 'Type of Recipient' + RecipientType : String(2); + /** + * Numbered assigned by the relevant authorities for exemption from withholding tax. + * + * This number must be entered in the system as follows:In the vendor master record in the case of vendorsFor customers, in Customizing under the settings for withholding tax information for the company code per withholding tax type. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'Exemption Number' + @sap.quickinfo : 'Exemption Certificate Number' + WithholdingTaxCertificate : String(25); + /** + * One or more "withholding tax codes" are assigned to each withholding tax type. One of the things these codes determine is the various percentage rates for the withholding tax type. + * + * Note that when processing a business transaction, no more than one withholding tax code can be assigned per withholding tax type. If the business transaction is subject to more than one withholding taxes, these must be represented in the system by defining various withholding tax types. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'W/Tax Code' + @sap.quickinfo : 'Withholding Tax Code' + WithholdingTaxCode : String(2); + /** + * Rate of exemption from withholding tax. + * + * Those persons/activities subject to withholding tax can be exempted from withholding tax up to the percentage rate you enter here. This exemption rate refers to the withholding tax amount itself and not to the whole amount liable to withholding tax (withholding tax base amount).The gross amount of an invoice is 100.00 and the withholding tax base amount is defined as gross. The withholding tax rate is 10% meaning that the withholding tax amount is 10.00. Given an exemption rate of 30%, the withholding tax amount is reduced to 7.00. + */ + @sap.label : 'Exemption Rate' + WithholdingTaxExmptPercent : Decimal(5, 2); + /** + * This is a number issued by the tax authorities per withholding tax type. + * + * This number must be specified in Customizing either:(a) As part of the withholding tax information defined for the company code, or(b) As part of the withholding tax information defined in the customer or vendor master record. + */ + @sap.display.format : 'UpperCase' + @sap.label : 'W/tax number' + @sap.quickinfo : 'Withholding tax identification number' + WithholdingTaxNumber : String(16); + /** The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. */ + @sap.display.format : 'UpperCase' + @sap.label : 'Authorization' + @sap.quickinfo : 'Authorization Group' + AuthorizationGroup : String(4); +}; + + diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/external/API_BUSINESS_PARTNER.edmx b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/external/API_BUSINESS_PARTNER.edmx new file mode 100644 index 000000000..5a6ddcc30 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/external/API_BUSINESS_PARTNER.edmx @@ -0,0 +1,3376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Internal key for identifying a Business Address Services address. + For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + + + + + Internal key for identifying a person in Business Address Services. + For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + + + + + + + Internet mail address, also called e-mail address. + Example: user.name@company.comThe Internet mail address is used to send mail via the Internet world-wide; the protocol used is SMTP (Simple Mail Transfer Protocol).The Internet mail address format is specified in various RFCs (Internet Request for Comment), including RFCs 821 and 822.This is not an IP address (192.56.30.6). + + + + + This field is generated by the system from the complete Internet mail address and is stored in table ADR6. + It contains the first 20 characters of the Internet mail address in normalized form, that is, without comment characters and converted into uppercase.The field cannot be maintained by the user or from an interface.The table ADR6 contains an index for this field.Using an Internet mail address, the corresponding key of table ADR6 and the owner of the address are determined (for example, business partner or user). + + + + + Additional information about the communication connection + You can maintain further information about the communication connection here. In the case of telephone numbers, for example, you can maintain the times at which the call recipient is available and those at which they are not, or you can specify whether the number is that of the secretary.The information is stored in table ADRT, regardless of language. + + + + + + + + + + + + Internal key for identifying a Business Address Services address. + For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + + + + + Internal key for identifying a person in Business Address Services. + For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + + + + + + If several addresses are maintained for one communication type, the user in the SAP System can be reached under one of these addresses. One address can be set as theStandard Address. + The standard address is used for the following functions:When sending using the SMTP nodein SAPconnect, the home address of the communication type used is the one set as the sender address. The recipient can see this address in the sender information and can also reply directly to this address. The standard address is also transferred and can be used for incoming status notifications, for example.When sending using an RFC node in SAPconnect, the standard address of the communication type used is the one set as the sender address. The structure defined in the case of the RFC does not permit another address to be transferred, so the standard address is used for incoming status notifications too.The SAP users have the addresses of their exchange P.O. boxes in their standard communication type 'Internet Mail' as the home address and their Internet address in the SAP system as their standard address. Example:Home address: Bernard.Brown@Company.comStandard address: Bernard.Brown@System.Company.comSending using an SMTP nodeThe home address of the communication type 'Internet Mail' (Bernard.Brown@Company.com) is used as the sender address. If a reply is sent to this address the user receives directly in the exchange postbox.Sending using the RFC nodeThe standard address of the communication type 'Internet Mail' (Bernard.Brown@System.Company.com) is used as the sender address. If a reply is sent to this address, it arrives back to the SAP system.Example using a mail system groupThe users should get all messages in their Microsoft Exchange postboxes. In the SAP system the mail system group is activated for this using the setting "Send Messages to the Home Address".The address settings of the SAP users remain unchanged:Home address: Bernard.Brown@Company.comStandard address: Bernard.Brown@System.Company.comSending using an SMTP nodeThe home address of the communication type 'Internet Mail' (Bernard.Brown@Company.com) is used as the sender address. If a reply is sent to this address the user receives directly in the exchange postbox.Sending using the RFC nodeThe standard address of the communication type 'Internet Mail' (Bernard.Brown@System.Company.com) is used as the sender address. If a reply is sent to this address it arrives back in the SAP system. It is then forwarded using the mail system group to the home address and the user gets it in the exchange postbox. + + + + + The country for the telephone number or fax number is maintained here. + This specification is used to determine the correct country code. A normalized form of the telephone number or fax number is then derived and stored in a field for a program-driven search.In most cases, the telephone number or fax number refers directly to an address.If this is the case, when a new number is created, the country of the address is proposed.If this is not the case (for example, with address-independent communication data for a business partner), the country from the user parameter LND is proposed (if it is maintained). If the user parameter LND is not maintained, the country of the company address assigned in the user master data is proposed.If the country of the address changes, the country of the corresponding telephone number and fax address is not changed automatically.Example: A business partner moves abroad.If the telephone number is for a permanent connection, the telephone number also changes when the business partner moves and has to be maintained again in the system.If the telephone number is for a mobile telephone and the number is retained, the original country for this telephone number also has to be retained and must not be changed automatically to the new country of the address. + + + + + Fax number, consisting of dialling code and number, but without country dialling code. + If the fax number consists of a company number and an extension, the extension must be entered in the field extension.Fax number, as it is to be dialled from within the same country.Enter the following for the number "01234/567-0":Fax: 01234/567Extension: 0Enter the following for the number "01234/567-891":Fax: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Fax: 012-345Extension: 678In the following cases, enter the complete number (without country dialing code) in the field Fax:No part of the number can be considered as an extension.You are not sure which part of the number can be considered as an extension. + + + + + Fax extension number + If the fax number consists of a company number and an extension, the extension must be entered here.Enter the extensionThe following rules apply for the format of telephone and fax numbers:The length of the entries in the field Telephone and Extension (Fax and Extension) cannot be more than 24 characters in total.Leading spaces are not allowed in the field Telephone or Fax or in the field Extension.Valid characters are:Numbers (0123456789)Letters (ABCDEFGHIJKLMNOPQRSTUVWXYZ)Following other characters: /, (, ), - *, # and " " (space), but not as a leading space.If an + is entered as the first character, the system checks whether the specified number starts with a country code. If so, a warning message is displayed because the country code is automatically determined by the system and should not be stored in the Telephone number (Fax number) field.If an & is entered as the first character, the automatic check and formatting of the telephone number (fax number), as well as the determination of the country code, is suppressed.Enter the following for the number "01234/567-0":Fax: 01234/567Extension: 0Enter the following for the number "01234/567-891":Fax: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Fax: 012-345Extension: 678In the following cases, enter the complete number (without country dialing code) in the field Fax:No part of the number can be considered as an extension.You are not sure which part of the number can be considered as an extension. + + + + + The content of this field is automatically calculated by the system based on fax number and country code components. + This field is therefore not to be filled when Business Address Services function modules are called. + + + + + Additional information about the communication connection + You can maintain further information about the communication connection here. In the case of telephone numbers, for example, you can maintain the times at which the call recipient is available and those at which they are not, or you can specify whether the number is that of the secretary.The information is stored in table ADRT, regardless of language. + + + + + + + + + + + + + + Internal key for identifying a Business Address Services address. + For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + + + + + Internal key for identifying a person in Business Address Services. + For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + + + + + + + + + Additional information about the communication connection + You can maintain further information about the communication connection here. In the case of telephone numbers, for example, you can maintain the times at which the call recipient is available and those at which they are not, or you can specify whether the number is that of the secretary.The information is stored in table ADRT, regardless of language. + + + + + + + + + + + + + + Internal key for identifying a Business Address Services address. + For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + + + + + Internal key for identifying a person in Business Address Services. + For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + + + + + + The country for the telephone number or fax number is maintained here. + This specification is used to determine the correct country code. A normalized form of the telephone number or fax number is then derived and stored in a field for a program-driven search.In most cases, the telephone number or fax number refers directly to an address.If this is the case, when a new number is created, the country of the address is proposed.If this is not the case (for example, with address-independent communication data for a business partner), the country from the user parameter LND is proposed (if it is maintained). If the user parameter LND is not maintained, the country of the company address assigned in the user master data is proposed.If the country of the address changes, the country of the corresponding telephone number and fax address is not changed automatically.Example: A business partner moves abroad.If the telephone number is for a permanent connection, the telephone number also changes when the business partner moves and has to be maintained again in the system.If the telephone number is for a mobile telephone and the number is retained, the original country for this telephone number also has to be retained and must not be changed automatically to the new country of the address. + + + + + If several addresses are maintained for one communication type, the user in the SAP System can be reached under one of these addresses. One address can be set as theStandard Address. + The standard address is used for the following functions:When sending using the SMTP nodein SAPconnect, the home address of the communication type used is the one set as the sender address. The recipient can see this address in the sender information and can also reply directly to this address. The standard address is also transferred and can be used for incoming status notifications, for example.When sending using an RFC node in SAPconnect, the standard address of the communication type used is the one set as the sender address. The structure defined in the case of the RFC does not permit another address to be transferred, so the standard address is used for incoming status notifications too.The SAP users have the addresses of their exchange P.O. boxes in their standard communication type 'Internet Mail' as the home address and their Internet address in the SAP system as their standard address. Example:Home address: Bernard.Brown@Company.comStandard address: Bernard.Brown@System.Company.comSending using an SMTP nodeThe home address of the communication type 'Internet Mail' (Bernard.Brown@Company.com) is used as the sender address. If a reply is sent to this address the user receives directly in the exchange postbox.Sending using the RFC nodeThe standard address of the communication type 'Internet Mail' (Bernard.Brown@System.Company.com) is used as the sender address. If a reply is sent to this address, it arrives back to the SAP system.Example using a mail system groupThe users should get all messages in their Microsoft Exchange postboxes. In the SAP system the mail system group is activated for this using the setting "Send Messages to the Home Address".The address settings of the SAP users remain unchanged:Home address: Bernard.Brown@Company.comStandard address: Bernard.Brown@System.Company.comSending using an SMTP nodeThe home address of the communication type 'Internet Mail' (Bernard.Brown@Company.com) is used as the sender address. If a reply is sent to this address the user receives directly in the exchange postbox.Sending using the RFC nodeThe standard address of the communication type 'Internet Mail' (Bernard.Brown@System.Company.com) is used as the sender address. If a reply is sent to this address it arrives back in the SAP system. It is then forwarded using the mail system group to the home address and the user gets it in the exchange postbox. + + + + + Telephone number, consisting of dialling code and number, but without country dialling code. + If the telephone number consists of a company number and an extension, the extension must be entered in the field extension.Telephone number, as it is dialled from within the country.For the number "01234/567-0" enter the following:Telephone: 01234/567Estension: 0For the number "01234/567-891" enter the following:Telephone: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Telepone: 012-345Extension: 678In the following cases enter the complete number (without country dialling code) in the field Telephone:No part of the number can be regarded as an extension.You are not sure which part of the number can be regarded as an extension. + + + + + Telephone extension number + If the telephone number consists of a company number and an extension, the extension should be entered here.Enter the extension.The following rules apply for the format of telephone and fax numbers:The length of the entries in the field Telephone and Extension (Fax and Extension) cannot be more than 24 characters in total.Leading spaces are not allowed in the field Telephone or Fax or in the field Extension.Valid characters are:Numbers (0123456789)Letters (ABCDEFGHIJKLMNOPQRSTUVWXYZ)Following other characters: /, (, ), - *, # and " " (space), but not as a leading space.If an + is entered as the first character, the system checks whether the specified number starts with a country code. If so, a warning message is displayed because the country code is automatically determined by the system and should not be stored in the Telephone number (Fax number) field.If an & is entered as the first character, the automatic check and formatting of the telephone number (fax number), as well as the determination of the country code, is suppressed.For the number "01234/567-0" enter the following:Telephone: 01234/567Estension: 0For the number "01234/567-891" enter the following:Telephone: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Telepone: 012-345Extension: 678In the following cases enter the complete number (without country dialling code) in the field Telephone:No part of the number can be regarded as an extension.You are not sure which part of the number can be regarded as an extension. + + + + + The content of this field is automatically calculated by the system based on the telephone number and country code components. + This field is therefore not to be filled when Business Address Services function modules are called. + + + + + This field specifies whether the telephone number is a mobile telephone number. + ' ' : The telephone number is a fixed-line telephone'1' : The telephone number is the standard fixed-line telephone'2' : The telephone nubmer is a mobile telephone'3' : The telephone number is the standard mobile telephoneEither the standard fixed-line telephone number or the standard mobile telephone number is also the standard telephone number (FLGDEFAULT = 'X').In older data sets, this field may have also have the value ' ' for the standard fixed-line telephone. In this case, however, FLGDEFAULT is always 'X'.In Customizing, you can specify whether the SMS-compatible indicator is to be proposed for new mobile telephone numbers created in dialog by choosing General Settings -> Set countries -> Define Mobile Telephone Attributes for each country. + + + + + Additional information about the communication connection + You can maintain further information about the communication connection here. In the case of telephone numbers, for example, you can maintain the times at which the call recipient is available and those at which they are not, or you can specify whether the number is that of the secretary.The information is stored in table ADRT, regardless of language. + + + + + + + + + + + + + + The business partner relationship number is an internal number that identifies the business partner relationship set. + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + + Internal key for identifying a Business Address Services address. + For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + + + + + Internal key for identifying a Business Address Services address. + For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + + + + + Additional address field which is printed above the Street line. + The Street address contains two lines above the street and two lines below the street.See Print the Street address. + + + + + Additional address field which is printed under the Street line. + The Street address has two lines above the street and two lines below the steet.See Print the Street address. + + + + + Time zone as part of an address. + The time zone is automatically determined by the system in address maintenance if time zone Customizing is maintained.It depends on the country and the region. (Region means state, province or county, depending on the country)The automatic determination is only made if there is no value in the time zone field. + + + + + Part of the address (c/o = care of) if the recipient is different from the occupant and the names are not similar (e.g. subtenants). + Put the country-specific code (e.g. c/o) in front of the name of the occupant. This is not automatically done in the print format, like the language-specific word "PO Box".John Smithc/o David BrownThis field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + + City name as part of the address. + The city name is saved redundantly in another database field in upper- case letters, for search help.If the Postal regional structure ('city file') is active, the city name is checked against the Cities defined in the regional structure. + + + + + Postal code that is assigned directly to one company (= company postal code = major customer postal code). + This field is used for countries where major companies are assigned their own postal code by the national post office.This postal code has to be entered in the field "Company Postal Code". Postal codes for group major customers, however, have to be entered in the field "PO Box Postal Code", since individual customers with a shared postal code for group major customers are differentiated by means of their PO box. + + + + + The country key contains information which the system uses to check entries such as the length of the postal code or bank account number. + The two-character ISO code in accordance with ISO 3166, which is delivered by SAP as a default, is usually used.It could also be the vehicle license plate country-code or a typical country key, for example, in Germany the Federal statistics office key.The country keys are determined at system installation in the global settings.The definition of the country key in the SAP system does not have to match political or government entities.Since the country key does not have to correspond to the ISO code in all installations, programs that differ according to certain values of the country key cannot query the country key T005-LAND1, but have to program based on the ISO code T005 INTCA. + + + + + Specifies the county’s name + This field is used to store the county’s name. You can enter the name of the county in this field. + + + + + The delivery service is part of the PO box address. + Some countries offer different services in addition to regular postal delivery and PO boxes, for example the Private Bag or Response Bag. If an address is related to one of these delivery services, the information about this particular delivery service has to be entered in the corresponding fields.In the field "Number of Delivery Service," the number of the Private Bag, Response Bag, or other relevant service has to be entered. Entering a number is not mandatory for each delivery service.For each address, either the information about the PO box or the information about the delivery service can be entered, but not both types of information at the same time.Mr PickeringPrivate Bag 106999Timaru 7942Delivery services will only be taken into account for address formatting in countries in which they are commonly used in addition to regular postal delivery and PO boxes, for example, in Australia, New Zealand, and the USA. In all other countries, these fields will not be taken into account for address formatting. + + + + + The delivery service is part of the PO box address. + Some countries offer different services in addition to regular postal delivery and PO boxes, for example the Private Bag or Response Bag. If an address is related to one of these delivery services, the information about this particular delivery service has to be entered in the corresponding fields.In the field "Type of Delivery Service," the type of the delivery service has to be entered.For each address, either the information about the PO box or the information about the delivery service can be entered, but not both types of information at the same time.Mr PickeringPrivate Bag 106999Timaru 7942Delivery services will only be taken into account for address formatting in countries in which they are commonly used in addition to regular postal delivery and PO boxes, for example, in Australia, New Zealand, and the USA. In all other countries, these fields will not be taken into account for address formatting. + + + + + City or District supplement + In some countries, this entry is appended with a hyphen to the city name by the automatic address formatting, other countries, it is output on a line of its own or (e.g. in the USA) not printed.See the examples in the Address Layout Key documentation. + + + + + Key for form of address text. + You can also define a form of address text in Customizing.The form of address text can be maintained in different languages. + + + + + This field contains the full name or formatted name of a party. + For organizations or document addresses, typically the fields Name1 and Name2 are concatenated.For persons the field contains the formatted name according to country specific rules. It corresponds e.g. to the content of the fields BUT000-NAME1_TEXT or ADRP-NAME_TEXT. + + + + + City of residence which is different from the postal city + In some countries, the residential city is required if it differs from the postal city.In the USA, the official street indexes, against which data can be checked, are based on the residential city, not the postal city, which may be different.It is the same in France, where a postally correct address must contain the residential city in a separate line above the postal city, if it differs from the postal city.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + House number as part of an address. + It is printed in the Street line.Other supplementary street information can be entered in the House number supplement or one of the Street2, Street3, Street4 or Street5 fields. See Print the Street address.A house number (e.g. 117) or a house number with supplement (e.g. 117a), or a house number range (e.g. 16-20), can be maintained in this field. + + + + + House number supplement as part of an address, e.g. + App. 17 orSuite 600.It is printed in the Street line.Further Street supplements can be put in one of the fields Street2, Street3, Street4 or Street5.See Print the Street address. + + + + + The language key indicates + - the language in which texts are displayed,- the language in which you enter texts,- the language in which the system prints texts. + + + + + PO Box number as part of an address. + Only enter the PO Box number in this field. The text "PO Box" is provided in the recipient language by the system when you print the address.When you print an address, the "Street address" and the "PO Box address" are distinguished. The print program determines which of them has priority if both are maintained in an address record.Besides the PO Box number, the PO Box address uses the following fields:PO Box postal code, if specified (otherwise the normal postal code)PO Box city, if specified (otherwise the normal city)PO Box region, if specified (otherwise the normal region)PO Box country, if specified (otherwise the normal country)If the address is a "PO Box" (without a number), do not fill the "PO Box" field. Select the "PO Box w/o Number" indicator instead.You can also enter a company postal code for organizational addresses, instead of a PO Box. A separate field is predefined for this entry.For general information and examples about address formatting, see the documentation on the Address Structure Key. + + + + + Different city for the PO Box as an address component. + The PO Box city can be entered here if it is different from the address city.If the address is only a PO Box address, enter the city in the normal city field.If the address contains two different city names for the address and the PO Box address, use this field. + + + + + Different PO Box country in address. + The PO Box country can be entered here, if it is different from the street address country.If the address only has a PO Box address, the country is in the normal country field.Use this field if the address has two different country values for the street address and the PO Box address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + Different Region for PO Box in an address. + Enter the PO Box Region here, if it differs from the street address region.If the address only has a PO Box address, the Region in in the normal Region field.Use this field if the address has two different Region values for the street address and the PO Box address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + PO Box address without PO Box number flag. + Only the word 'PO Box' is output in PO Box addresses without PO Box number.Set this flag for a PO Box address without PO Box number.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + The PO box lobby is part of the PO box address. + In some countries, entering a PO box, postal code and city is not sufficient to uniquely identify a PO box, because the same PO box number is assigned multiple times in some cities.Therefore, additional information might be required to determine the post office of the PO box in question. This information can be entered in the field "PO Box Lobby."Mr NellingPO Box 4099HighfieldTimaru 7942The PO box lobby will only be taken into account for address formatting in countries in which it is commonly used in addition to regular postal delivery and PO boxes, for example, in Canada or New Zealand. In all other countries, this field will not be taken into account for address formatting. + + + + + Postal code that is required for a unique assignment of the PO box. + This field is used for countries where a different postal code applies to mail that is sent to the PO box rather than to the street address of a particular business partner.Postal codes for group major customers also have to be entered in the field for the PO box postal code since individual customers with a shared postal code for group major customers are differentiated by means of the PO box. Postal codes for major customers (= company postal codes), however, are assigned to one customer only and have to be entered in the field 'Company Postal Code'. + + + + + Internal key for identifying a person in Business Address Services. + For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + + + + + Postal code as part of the address + If different postal codes are maintained for the PO Box and Street address of an address, this field contains the Street address postal code. + + + + + Communication method with which you can exchange documents and messages with a business partner. + In Business Address Services, you can specify a standard communication method that can be used by programs to determine the means of communication for sending messages.One business partner wants all messages by fax, another by e-mail.The application context can restrict the possible methods of communication. For example, invitations should perhaps only be sent by post because of enclosures, whereas minutes can be sent by post, fax or e-mail.Communication strategies can be defined for this purpose and applied in application contexts. + + + + + In some countries, the region forms part of the address. The meaning depends on the country. + The automatic address formatting function prints the region in addresses in the USA, Canada, Italy, Brazil or Australia, and the county in Great Britain.For more information, see the examples in the documentation on the Address Layout Key.Meaning of the regional code in ...Australia -> ProvinceBrazil -> StateCanada -> ProvinceGermany -> StateGreat Britain -> CountyItaly -> ProvinceJapan -> PrefectureSwitzerland -> CantonUSA -> State + + + + + Street name as part of the address. + The street name is saved, redundantly in upper case in another database field, for search help purposes.There are other fields for address parts which can be printed above or below the street. See Print the Street address.The house number and other supplements are usually maintained in their own fields. See Formatting the Street line. + + + + + Additional address field which is printed above the Street line. + The Street address contains two lines above the street and two lines below the street.See Print the Street address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + Additional address field which is printed below the Street line. + The Street address contains two lines above the street and two lines below the street.See Print the Street address. + + + + + Specifies the tax jurisdiction. + + + + + + Sales and distribution: + Regional zone of Goods recipient.Purchasing:Regional zone of supplier.You can define regional zones to suit the requirements of your own business and country.Sales and distributionthe system automatically proposes a suitable route by using the transportation zone of the goods recipient in combination with other information about the delivery, such as theCountries of origin and destinationShipping conditionsTransportation groupIn the USA, for example, you can define regional zones to correspond to the US postal zip codes. + + + + + + + + + + + + + + + + + + The business partner relationship number is an internal number that identifies the business partner relationship set. + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + + Identifies the function that a person has within a company. + This is a contact person attribute that you can define in Customizing.Personnel managerSecretary + + + + + Name of the department of a business partner for your internal usage. + The name given by the business partner to this particular department may differ from the name that you use. You can enter the name given by the business partner in the field company department.This is a contact person attribute that you can define in Customizing.For your purposes, the department name is "Sales". The business partner names the same department "Sales South". + + + + + Telephone number, consisting of dialling code and number, but without country dialling code. + If the telephone number consists of a company number and an extension, the extension must be entered in the field extension.Telephone number, as it is dialled from within the country.For the number "01234/567-0" enter the following:Telephone: 01234/567Estension: 0For the number "01234/567-891" enter the following:Telephone: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Telepone: 012-345Extension: 678In the following cases enter the complete number (without country dialling code) in the field Telephone:No part of the number can be regarded as an extension.You are not sure which part of the number can be regarded as an extension. + + + + + Telephone extension number + If the telephone number consists of a company number and an extension, the extension should be entered here.Enter the extension.The following rules apply for the format of telephone and fax numbers:The length of the entries in the field Telephone and Extension (Fax and Extension) cannot be more than 24 characters in total.Leading spaces are not allowed in the field Telephone or Fax or in the field Extension.Valid characters are:Numbers (0123456789)Letters (ABCDEFGHIJKLMNOPQRSTUVWXYZ)Following other characters: /, (, ), - *, # and " " (space), but not as a leading space.If an + is entered as the first character, the system checks whether the specified number starts with a country code. If so, a warning message is displayed because the country code is automatically determined by the system and should not be stored in the Telephone number (Fax number) field.If an & is entered as the first character, the automatic check and formatting of the telephone number (fax number), as well as the determination of the country code, is suppressed.For the number "01234/567-0" enter the following:Telephone: 01234/567Estension: 0For the number "01234/567-891" enter the following:Telephone: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Telepone: 012-345Extension: 678In the following cases enter the complete number (without country dialling code) in the field Telephone:No part of the number can be regarded as an extension.You are not sure which part of the number can be regarded as an extension. + + + + + Fax number, consisting of dialling code and number, but without country dialling code. + If the fax number consists of a company number and an extension, the extension must be entered in the field extension.Fax number, as it is to be dialled from within the same country.Enter the following for the number "01234/567-0":Fax: 01234/567Extension: 0Enter the following for the number "01234/567-891":Fax: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Fax: 012-345Extension: 678In the following cases, enter the complete number (without country dialing code) in the field Fax:No part of the number can be considered as an extension.You are not sure which part of the number can be considered as an extension. + + + + + Fax extension number + If the fax number consists of a company number and an extension, the extension must be entered here.Enter the extensionThe following rules apply for the format of telephone and fax numbers:The length of the entries in the field Telephone and Extension (Fax and Extension) cannot be more than 24 characters in total.Leading spaces are not allowed in the field Telephone or Fax or in the field Extension.Valid characters are:Numbers (0123456789)Letters (ABCDEFGHIJKLMNOPQRSTUVWXYZ)Following other characters: /, (, ), - *, # and " " (space), but not as a leading space.If an + is entered as the first character, the system checks whether the specified number starts with a country code. If so, a warning message is displayed because the country code is automatically determined by the system and should not be stored in the Telephone number (Fax number) field.If an & is entered as the first character, the automatic check and formatting of the telephone number (fax number), as well as the determination of the country code, is suppressed.Enter the following for the number "01234/567-0":Fax: 01234/567Extension: 0Enter the following for the number "01234/567-891":Fax: 01234/567Extension: 891For the number "012-345-678" (678 as extension) enter the following:Fax: 012-345Extension: 678In the following cases, enter the complete number (without country dialing code) in the field Fax:No part of the number can be considered as an extension.You are not sure which part of the number can be considered as an extension. + + + + + Internet mail address, also called e-mail address. + Example: user.name@company.comThe Internet mail address is used to send mail via the Internet world-wide; the protocol used is SMTP (Simple Mail Transfer Protocol).The Internet mail address format is specified in various RFCs (Internet Request for Comment), including RFCs 821 and 822.This is not an IP address (192.56.30.6). + + + + + A relationship may exist between two business partners. The business partner relationship category characterizes the features of the relationship. + A distinction is made between a one-way and an undirected business partner relationship category. In a one-way relationship category, the relationship extends from one partner to another, but not vice versa.Marriage (undirected)Employee (one-way)Contact person (one-way) + + + + + + + + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + + Business partner attribute, which you can use to distinguish between various addresses by defining the address usage for communication with business partners. + Maintain the usage types for addresses (address types) in Customizing.You can create a short description and a name for the address type.When maintaining business partners you can use the function address usage to assign business partner addresses to address types.If necessary, you can set the indicator for multiple use in Customizing.Correspondence addressDelivery address + + + + + Internal key for identifying a Business Address Services address. + For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + + + + + + Establishes which is the standard address for an address usage. + Several addresses per period can be assigned to an address usage.If this is the case, then this indicator controls which of the assigned addresses should be the standard address of the relevant usage. This is determined automatically when the address usage is accessed. + + + + + You can use authorization groups to stipulate which business partners a user is allowed to process. + Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + + + + + + + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + A document (such as an ID card or driver's license) or an entry in a system of records (such as a commercial register) whose key can be stored as an attribute for a business partner. + The identification type is for classifying identification numbers.You can define the identification types and their descriptions in Customizing.You can also specify for which business partner category an ID type should be valid.If necessary, assign the identification type to an Identification Category.You can only assign one identification type to an identification category. + + + + + Number that serves to identify a business partner, such as driver's license, or ID card number. + + + + + + Institution that adminsters or assigns an ID number. + + + + + + Date on which the ID number was registered or assigned by the appropriate authority. + + + + + + Country in which an ID number was assigned, or in which the number is valid. + + + + + + In some countries, the region forms part of the address. The meaning depends on the country. + The automatic address formatting function prints the region in addresses in the USA, Canada, Italy, Brazil or Australia, and the county in Great Britain.For more information, see the examples in the documentation on the Address Layout Key.Meaning of the regional code in ...Australia -> ProvinceBrazil -> StateCanada -> ProvinceGermany -> StateGreat Britain -> CountyItaly -> ProvinceJapan -> PrefectureSwitzerland -> CantonUSA -> State + + + + + This date marks the start of validity of an ID number. + + + + + + This date marks the end of validity of an ID number. + + + + + + You can use authorization groups to stipulate which business partners a user is allowed to process. + Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + + + + + + + + + + + + Describes an industry. + An industry is a classification of companies according to their main business activity. For example, you can use Commerce, Banking, Services, Industry, Healthcare, Public Sector, Media, and so on, as industries.You can define industries along with their descriptions in Customizing.Assign the industry key to an industry key system. + + + + + Serves to combine and categorize several industries into a group. + You can create different industry systems, each with its own catalog of industries, whereby an industry can be assigned to several industry systems.You have to select one industry system as the standard industry system. This is then automatically displayed in the initial screen for the maintenance of industry data.You can define an industry system along with its description in Customizing. You can assign several industry systems to a business partner.If you choose the button All Industry Systems, you can access all the industry systems defined in the Customizing using the input help. + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + Identifies the industry in an industry system that can be defined as the standard industry. + It is recommended that you define an industry within an industry system as the standard industry, because only the standard industries can be determined at the interfaces to BW or the APIs, for example.This means that even if only one industry exists within an industry system, it should be indicated as the standard industry as this this information cannot be determined otherwise. + + + + + + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. + + + + + + Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. + + + + + + Key for academic title. + You can define a key for an academic title in Customizing. + + + + + You can use authorization groups to stipulate which business partners a user is allowed to process. + Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + + + + + Category under which a business partner is classified. + You can distinguish between the following business partner categories:OrganizationNatural personGroup of natural persons or organizationsThe processing screens for the business partner categories are set up differently.So, for example, the screen for an organization contains the field Legal form, but this is not needed in the screen for a natural person. + + + + + + Classification assigned when creating a business partner. + Assign each business partner to a grouping when you create the business partner. The grouping determines the number range. You cannot change the assignment afterwards.You can define the groupings, their descriptions, the associated number range and other attributes in Customizing.You can define standard groupings for the internal and the external number assignment.For each grouping create a number range.When you create a business partner, the entry in the grouping field determines whether and how an entry is made in the business partner number field. + + + + + + + Correspondence language (written) for business partners in the 'Person' category. Maintain the correspondence language for business partners in the 'Organization' and 'Group' category with the address (communication). + When transferring data (direct input), make sure that for a'Person', the field 'LANGU_CORR' and for an'Organization' or "Group" the field 'LANGU'has an entry. + + + + + + + + + Key for form of address text. + You can also define a form of address text in Customizing.The form of address text can be maintained in different languages. + + + + + An industry sector is the term used to classify a company according to its main business activity. + You can assign an industry sector to business partners in the category 'Organization'RetailBanksServicesIndustryHealth servicePublic sectorMedia + + + + + Here you enter the first 7 digits of the international location number. + The International Location Number (ILN) is assigned (in Germany by the Centrale for Coorganisation GmbH)) when a company is founded. It consists of 13 digits, the last digit being the check digit. There are two categories of location numbers:Participants who only need an ILN to cleary and unmistakably identify themselves for communication with the business partner are given a category 1 ILN. This cannot be used to identify articles by means of EAN.Participants who wish to assign the location numbers for their own enterprise areas are given a category 2 ILN. For a category 2 ILN, digits 1 to 7 are described as basis number. This is used as basis for the creation of article numbers (EAN). + + + + + Here, you enter digits 8-12 of the 13-digit international location number. + The international location number (ILN) is assigned when establishing a company (by the "Zentrale für Coorganisation GmbH" in Germany). It consists of 13 digits, the last of which is the check digit. There are two types of international location numbers:Subscribers who only need one ILN to identify themselves in communication with the business partner are given an ILN of type 1. These cannot be used for identifying articles by means of EAN.Subscribers who need to assign location numbers for their own company areas are given an ILN of type 2. Positions 1 through 7 of the ILN type 2 are known as the basis number. This basis number forms the basis for article numbers (EAN). + + + + + + + Indicator through which a distinction between natural and legal persons can be made during tax reporting. + Is used in Italy and Mexico ,among other countries.Brasil: If the indicator is not set, 'CGC' is relevant in tax number 1. If the indicator is set, 'CPF' is relevant in tax number 2.Colombia: In the case of some natural persons, the NIT number does not have a check digit. In this case you should set this indicator and the check is deactivated. + + + + + + + Language for verbal communication with a business partner. + This language may differ from the language(s) defined for written correspondence. + + + + + + + + + Denotes certain legal norms that are of significance for the organization of a company. + For business partners in the category "Organization", you can state the legal form of the company. This is for information purposes only.Stock corporation (AG in Germany)Limited liability company (GmbH in Germany) + + + + + First name field for business partners in the Organization category. + + + + + + Second name field for business partners in the Organization category. + + + + + + Third name field for business partners in the Organization category. + + + + + + Fourth name field for business partners in the Organization category. + + + + + + Indicates the official registration of a company in the Commercial Register. + If a company is not officially registered in the Commercial Register, it has to use some type of text addition, such as foundation pending, when referring to the legal form. + + + + + Term for the end of bankruptcy proceedings. + This date also indicates that the company no longer exists. + + + + + Denotes the term that you define for a business partner, and via which you can restrict the search for a business partner in the business partner search or in the locator. + + + + + + Denotes the term that you define for a business partner, and via which you can restrict the search for a business partner in the business partner search or in the locator. + + + + + + + + + If the business partner is blocked centrally, certain activities cannot be executed. + + + + + + You can use the business partner type to group business partners according to your own criteria in Customizing (IMG). + In Customizing you can show or hide fields for data entry, depending on the requirements of the relevant business partner type.Select a business partner type. You can obtain help by pressing the F4 key. + + + + + + First name field for business partners in the Group category. + + + + + + Second name field for business partners in the Group category. + + + + + + Internal key for identifying the address for communication data that spans all addresses in Business Partner. + For more information on the significance and usage of the address number, see the documentation for Business Address Services (BAS). + + + + + The check digit is derived from a special check digit procedure from digits of the previous international location numbers. In this way, you can check whether the ILN entered is actually valid. + + + + + + + The name format rule country and the name format rule key together uniquely identify a formatting rule. + A country can have several formats which correspond to different rules. Formatting rules describe the format of a person name. + + + + + See Name format. + + + + + + States the complete name of a person. + The complete name is generally generated and saved by the Business Address Services (BAS) according to country-specific rules from the individual name components (without the form of address).If, during the formatting of an address, you want to use an alternative name, you can manually format the alternative name here. + + + + + Internal key for identifying a person in Business Address Services. + For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + + + + + Establishes if the business partner is meant to be archived. + If the indicator is set, the relevant business partner can be archived from the view of the business partner administration.If the check of the data to be archived shows, for example, that there are still active business transactions the archiving of the business partner data is prevented even if the indicator is set.If the indicator is not set, the business partner will not be taken into consideration during archiving. + + + + + Business partner number from an external system or a legacy system. + If the current business partner is known under a different number in an external system, you can store this number here for information purposes.Direct input gives you the option of maintaining a business partner by specifying the external business partner number. If you maintain business partner data in your legacy system, you can transmit changes made to business partners to the SAP system without having to know the SAP business partner number in the legacy system. + + + + + Company ID standard for the whole group. + + + + + + + + + + + + + + + + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + Internal key for identifying a Business Address Services address. + For more information about the meaning and use of the address number and the Business Address Services concepts, see the function group SZA0 documentation. + + + + + + + You can use authorization groups to stipulate which business partners a user is allowed to process. + Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + + + + + + Additional address field which is printed above the Street line. + The Street address contains two lines above the street and two lines below the street.See Print the Street address. + + + + + Additional address field which is printed under the Street line. + The Street address has two lines above the street and two lines below the steet.See Print the Street address. + + + + + Time zone as part of an address. + The time zone is automatically determined by the system in address maintenance if time zone Customizing is maintained.It depends on the country and the region. (Region means state, province or county, depending on the country)The automatic determination is only made if there is no value in the time zone field. + + + + + Part of the address (c/o = care of) if the recipient is different from the occupant and the names are not similar (e.g. subtenants). + Put the country-specific code (e.g. c/o) in front of the name of the occupant. This is not automatically done in the print format, like the language-specific word "PO Box".John Smithc/o David BrownThis field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + + City name as part of the address. + The city name is saved redundantly in another database field in upper- case letters, for search help.If the Postal regional structure ('city file') is active, the city name is checked against the Cities defined in the regional structure. + + + + + Postal code that is assigned directly to one company (= company postal code = major customer postal code). + This field is used for countries where major companies are assigned their own postal code by the national post office.This postal code has to be entered in the field "Company Postal Code". Postal codes for group major customers, however, have to be entered in the field "PO Box Postal Code", since individual customers with a shared postal code for group major customers are differentiated by means of their PO box. + + + + + The country key contains information which the system uses to check entries such as the length of the postal code or bank account number. + The two-character ISO code in accordance with ISO 3166, which is delivered by SAP as a default, is usually used.It could also be the vehicle license plate country-code or a typical country key, for example, in Germany the Federal statistics office key.The country keys are determined at system installation in the global settings.The definition of the country key in the SAP system does not have to match political or government entities.Since the country key does not have to correspond to the ISO code in all installations, programs that differ according to certain values of the country key cannot query the country key T005-LAND1, but have to program based on the ISO code T005 INTCA. + + + + + Specifies the county’s name + This field is used to store the county’s name. You can enter the name of the county in this field. + + + + + The delivery service is part of the PO box address. + Some countries offer different services in addition to regular postal delivery and PO boxes, for example the Private Bag or Response Bag. If an address is related to one of these delivery services, the information about this particular delivery service has to be entered in the corresponding fields.In the field "Number of Delivery Service," the number of the Private Bag, Response Bag, or other relevant service has to be entered. Entering a number is not mandatory for each delivery service.For each address, either the information about the PO box or the information about the delivery service can be entered, but not both types of information at the same time.Mr PickeringPrivate Bag 106999Timaru 7942Delivery services will only be taken into account for address formatting in countries in which they are commonly used in addition to regular postal delivery and PO boxes, for example, in Australia, New Zealand, and the USA. In all other countries, these fields will not be taken into account for address formatting. + + + + + The delivery service is part of the PO box address. + Some countries offer different services in addition to regular postal delivery and PO boxes, for example the Private Bag or Response Bag. If an address is related to one of these delivery services, the information about this particular delivery service has to be entered in the corresponding fields.In the field "Type of Delivery Service," the type of the delivery service has to be entered.For each address, either the information about the PO box or the information about the delivery service can be entered, but not both types of information at the same time.Mr PickeringPrivate Bag 106999Timaru 7942Delivery services will only be taken into account for address formatting in countries in which they are commonly used in addition to regular postal delivery and PO boxes, for example, in Australia, New Zealand, and the USA. In all other countries, these fields will not be taken into account for address formatting. + + + + + City or District supplement + In some countries, this entry is appended with a hyphen to the city name by the automatic address formatting, other countries, it is output on a line of its own or (e.g. in the USA) not printed.See the examples in the Address Layout Key documentation. + + + + + Key for form of address text. + You can also define a form of address text in Customizing.The form of address text can be maintained in different languages. + + + + + This field contains the full name or formatted name of a party. + For organizations or document addresses, typically the fields Name1 and Name2 are concatenated.For persons the field contains the formatted name according to country specific rules. It corresponds e.g. to the content of the fields BUT000-NAME1_TEXT or ADRP-NAME_TEXT. + + + + + City of residence which is different from the postal city + In some countries, the residential city is required if it differs from the postal city.In the USA, the official street indexes, against which data can be checked, are based on the residential city, not the postal city, which may be different.It is the same in France, where a postally correct address must contain the residential city in a separate line above the postal city, if it differs from the postal city.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + House number as part of an address. + It is printed in the Street line.Other supplementary street information can be entered in the House number supplement or one of the Street2, Street3, Street4 or Street5 fields. See Print the Street address.A house number (e.g. 117) or a house number with supplement (e.g. 117a), or a house number range (e.g. 16-20), can be maintained in this field. + + + + + House number supplement as part of an address, e.g. + App. 17 orSuite 600.It is printed in the Street line.Further Street supplements can be put in one of the fields Street2, Street3, Street4 or Street5.See Print the Street address. + + + + + The language key indicates + - the language in which texts are displayed,- the language in which you enter texts,- the language in which the system prints texts. + + + + + PO Box number as part of an address. + Only enter the PO Box number in this field. The text "PO Box" is provided in the recipient language by the system when you print the address.When you print an address, the "Street address" and the "PO Box address" are distinguished. The print program determines which of them has priority if both are maintained in an address record.Besides the PO Box number, the PO Box address uses the following fields:PO Box postal code, if specified (otherwise the normal postal code)PO Box city, if specified (otherwise the normal city)PO Box region, if specified (otherwise the normal region)PO Box country, if specified (otherwise the normal country)If the address is a "PO Box" (without a number), do not fill the "PO Box" field. Select the "PO Box w/o Number" indicator instead.You can also enter a company postal code for organizational addresses, instead of a PO Box. A separate field is predefined for this entry.For general information and examples about address formatting, see the documentation on the Address Structure Key. + + + + + Different city for the PO Box as an address component. + The PO Box city can be entered here if it is different from the address city.If the address is only a PO Box address, enter the city in the normal city field.If the address contains two different city names for the address and the PO Box address, use this field. + + + + + Different PO Box country in address. + The PO Box country can be entered here, if it is different from the street address country.If the address only has a PO Box address, the country is in the normal country field.Use this field if the address has two different country values for the street address and the PO Box address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + Different Region for PO Box in an address. + Enter the PO Box Region here, if it differs from the street address region.If the address only has a PO Box address, the Region in in the normal Region field.Use this field if the address has two different Region values for the street address and the PO Box address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + PO Box address without PO Box number flag. + Only the word 'PO Box' is output in PO Box addresses without PO Box number.Set this flag for a PO Box address without PO Box number.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + The PO box lobby is part of the PO box address. + In some countries, entering a PO box, postal code and city is not sufficient to uniquely identify a PO box, because the same PO box number is assigned multiple times in some cities.Therefore, additional information might be required to determine the post office of the PO box in question. This information can be entered in the field "PO Box Lobby."Mr NellingPO Box 4099HighfieldTimaru 7942The PO box lobby will only be taken into account for address formatting in countries in which it is commonly used in addition to regular postal delivery and PO boxes, for example, in Canada or New Zealand. In all other countries, this field will not be taken into account for address formatting. + + + + + Postal code that is required for a unique assignment of the PO box. + This field is used for countries where a different postal code applies to mail that is sent to the PO box rather than to the street address of a particular business partner.Postal codes for group major customers also have to be entered in the field for the PO box postal code since individual customers with a shared postal code for group major customers are differentiated by means of the PO box. Postal codes for major customers (= company postal codes), however, are assigned to one customer only and have to be entered in the field 'Company Postal Code'. + + + + + Internal key for identifying a person in Business Address Services. + For more information about the meaning and use of the person number and Business Address Services concepts, see the function group SZA0 documentation. + + + + + Postal code as part of the address + If different postal codes are maintained for the PO Box and Street address of an address, this field contains the Street address postal code. + + + + + Communication method with which you can exchange documents and messages with a business partner. + In Business Address Services, you can specify a standard communication method that can be used by programs to determine the means of communication for sending messages.One business partner wants all messages by fax, another by e-mail.The application context can restrict the possible methods of communication. For example, invitations should perhaps only be sent by post because of enclosures, whereas minutes can be sent by post, fax or e-mail.Communication strategies can be defined for this purpose and applied in application contexts. + + + + + In some countries, the region forms part of the address. The meaning depends on the country. + The automatic address formatting function prints the region in addresses in the USA, Canada, Italy, Brazil or Australia, and the county in Great Britain.For more information, see the examples in the documentation on the Address Layout Key.Meaning of the regional code in ...Australia -> ProvinceBrazil -> StateCanada -> ProvinceGermany -> StateGreat Britain -> CountyItaly -> ProvinceJapan -> PrefectureSwitzerland -> CantonUSA -> State + + + + + Street name as part of the address. + The street name is saved, redundantly in upper case in another database field, for search help purposes.There are other fields for address parts which can be printed above or below the street. See Print the Street address.The house number and other supplements are usually maintained in their own fields. See Formatting the Street line. + + + + + Additional address field which is printed above the Street line. + The Street address contains two lines above the street and two lines below the street.See Print the Street address.This field is not always automatically printed, as it was subsequently added to the address structure.The print program or form may need to be adjusted.This exception applies to the following fields:Street2, Street3, Street4, Street5, c/o name, and to all address fields added after Release 4.5. + + + + + Additional address field which is printed below the Street line. + The Street address contains two lines above the street and two lines below the street.See Print the Street address. + + + + + Specifies the tax jurisdiction. + + + + + + Sales and distribution: + Regional zone of Goods recipient.Purchasing:Regional zone of supplier.You can define regional zones to suit the requirements of your own business and country.Sales and distributionthe system automatically proposes a suitable route by using the transportation zone of the goods recipient in combination with other information about the delivery, such as theCountries of origin and destinationShipping conditionsTransportation groupIn the USA, for example, you can define regional zones to correspond to the US postal zip codes. + + + + + Address number from an external system or a legacy system + If the current address has a different number in an external system, you can save this number here for information purposes.In direct input you are able to maintain an address for a business partner by stating the external address number. If your business partner data is maintained in a legacy system, you can thus transmit changes to a BP address to the SAP system without having to know the SAP address number in the legacy system. + + + + + + + + + + + + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + Key identifying a business partner's bank details. + Enter a bank details ID for each separate set of bank details for a business partner.Business Partner: H. MillerBD-ID Fin.institution Acct no. 0001 Chemical Bank, NYC 56234560002 Chemical Bank, NYC 56231220003 First Bank of Pittsburgh ...Business partner: T.Wolsey and Co.BD-ID Fin.institution Acct no.GIR0 Citibank, Charleston ...GIR1 Chemical Bank, NYC ... + + + + + Identifies the country in which the bank is based. + The country key determines according to which rules the remaining bank data (for example, bank number and bank account number) is checked. + + + + + The name under which the bank operates. + + + + + + The bank key (under which the bank data is stored in the appropriate country) is specified in this field. + The country-specific meaning of this bank key is specified when defining country key.Normally banks have a bank number, which then also appears in the control data of the bank.In certain countries the bank account number assumes this function; in such a case there would be no bank numbers, the bank details are then under the account number.For data medium exchange it can be useful to be able create banks for foreign business partners without a bank number, even if the country in question has bank numbers. In such cases the bank key can be assigned internally.If the bank data is under another key, such as the SWIFT code for example, numbers can also be assigned externally. + + + + + Uniquely identifies a bank throughout the world. + SWIFT stands for Society for Worldwide Interbank Financial Telecommunication.BIC stands for Bank Identifier Code.This globally unique code can be used in international payment transactions to identify the bank without the need to specify an address or bank number. Specification of the SWIFT code/BIC is mainly relevant for automatic payment transactions. + + + + + Brazil, France, Spain, Portugal and Italy + The field contains a check key for the combination bank number and bank account number.USAIn USA this field is used to differentiate between a savings and a current account (if no value is entered, the default value 01 is used).01 Current account02 Savings account03 Loan account04 General ledgerJapanIn Japan this field specifies the type of account. This information is is copied from the payment medium print program into payment medium. The following is an example of the account types used:01 FUTSU (similar to a savings account)02 TOUZA (similar to a current account)04 CHOCHIKU (similar to an investment account)09 Other types of bank accountsSouth AfricaIn South Africa this field specifies the type of account. The information entered here is forwarded to the bank that carries out the payment order. The following account types are permitted in ABC format:01 Current (Cheque) Account02 Savings Account03 Transmission Account04 Bond Account06 Subscription Share AccountArgentinaIn Argentina this field specifies the type of account:CC Current Account (Cuenta corriente)CA Saving Account (Caja de ahorro)CE Special Saving Account (Caja de ahorro especial)CS Salary Account (Cuenta sueldos)VenezuelaIn Venezuela this field specifies the type of account:CC Checking Account (Cuenta corriente)CA Saving Account (Cuenta de ahorro)CE Special Saving Account (Cuenta de ahorro especial)CS Salary Account (Cuenta sueldos)MexicoIn Mexico this field contains a two-digit key for classifying the bank account (for example, as a savings or current account). This key have different definitions, depending on the bank.NoteFor countries that are not listed here, this field can be used for account-specific information. + + + + + Here you can enter another name that the payment program can use if the name of the account holder is not the same as the name of the Business Partner. + + + + + + + + + A uniform standardized ID number for representing bank details that is in accordance with the ECBS (European Committee for Banking Standards). An IBAN has a maximum of 34 alphanumeric characters and is a combination of the following elements: + Country key of the bank (ISO code)Two-digit check numberCountry-specific account number (in Germany this consists of the bank number and account number, in France the bank number, account number and check key).The IBAN not only makes international payments easier, in some countries it has advantages for domestic payments as well. Depending on the country, it can mean advantages for value and fees.The IBAN can be maintained in parallel with the bank details but does not replace them. It is stored under the master data of the business partner and can then be used when creating the payment medium.Since it is only the bank that has the account that may generate the IBAN corresponding to an account number, the SAP system only generates a proposal. You can confirm or change this proposal. If no proposal is generated, enter the IBAN manually.An IBAN in Belgium may look like this:Electronic Form:BE62510007547061Printed form, as it would appear on an invoice:IBAN BE62 5100 0754 7061 + + + + + + This field contains the number under which the account is managed at the bank. + + + + + + Additional details for the bank details of the business partner. + In some countries the data for the bank details of the business partner (bank number, bank account number, name of the account holder) have to supplemented by other details in order to be able to use certain payment processes. This supplementary details are defined here.If additional data is required for the bank details for payment transactions in your country (see the following examples), enter the reference information.If for an automatic debit the bank requires the reference number of the collection authorization in Norway or Great Britain, specify this number here.In Great Britain when making payments to an account in a 'Building Society' you must specify which number payment recipient has. These details must be defined in the reference field, whereas the fields Bank Key and Account Number are to be used for the bank details of the 'Building Society'.In Great Britain when entering a building society account number, the name of the building society should also be maintained in the system. + + + + + States that the bank has collection authorization from the business partner for the account. + Set this indicator if the bank has collection authorization.Note for Accounts Receivable (FI-AR)If this indicator is not set, there is no bank collection.Note for Contract Accounts Receivable and Payable (FI-CA)This indicator is not relevant. + + + + + Name of the city as a part of the address. + + + + + + You can use authorization groups to stipulate which business partners a user is allowed to process. + Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + + + + + + + + + + + + + The business partner relationship number is an internal number that identifies the business partner relationship set. + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + + + States whether the relationship is a standard relationship. + If several relationships of the BP relationship category contact person have been defined for, you can set the indicator standard relationship for one of these relationships.A relationship that is marked as a standard relationship can be used whenA certain scenario automatically selects a contact personThe contact person responsible is not knownYou can give this indicator to only one business partner relationship of a BP relationship category for a particular period. Another relationship of the same relationship category can be indicated as the standard relationship only if the periods for the relationship do not overlap or coincide. + + + + + A relationship may exist between two business partners. The business partner relationship category characterizes the features of the relationship. + A distinction is made between a one-way and an undirected business partner relationship category. In a one-way relationship category, the relationship extends from one partner to another, but not vice versa.Marriage (undirected)Employee (one-way)Contact person (one-way) + + + + + + + + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + Function that a business partner takes on, depending on a business transaction. + You can define business partner roles along with their attributes in Customizing.You can create an alphanumeric, 6-digit key for the BP role. You can also choose a title as the short form and a description as the long form for the role text.Screen control in the dialog takes place by assigning a BP view.A program can access specific business partner roles for a business partner using thebusiness partner role category . The role categories are also in the TB003 table. + + + + + + + You can use authorization groups to stipulate which business partners a user is allowed to process. + Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + + + + + + + + + + + Key identifying a business partner in the SAP system. The key is unique within a client. + + + + + + Specifies the tax number category. + + + + + + Specifies the tax number. + + + + + + Specifies the tax number. + You can enter up to 60 characters in this field. + + + + + You can use authorization groups to stipulate which business partners a user is allowed to process. + Use the following authorization object:'Business partners: authorization groups' (B_BUPA_GRP).The system only checks this authorization if you made an entry in the "Authorization group" field for the business partner. Otherwise, any user may process the business partner. + + + + + + + + + + Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. + + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + Indicates if the processing of billing documents is blocked for the customer in all sales areas (company-wide, for example). + You can define different kinds of block, according to the needs of your organization. You can, for example, automatically block the processing of all credit memos to a certain customer, pending manual approval. + + + + + Name with which the user who entered the master record was logged on in the R/3 System. + + + + + + Date on which the master record, or the part of the master record being viewed, was created. + + + + + + The account group is a classifying feature within customer master records. The account group determines: + in which number range the customer account number should be;whether the number is assigned by the user or by the system;which specifications are necessary or possible in the master record. + + + + + Specifies a classification of the customer (for example, classifies the customer as a bulk purchaser). + The classifications are freely definable according to the needs of your organization. + + + + + + + Indicates if delivery processing is blocked for the customer in all sales areas (company-wide, for example). + You can define different kinds of block, according to the needs of your organization. You can, for example, automatically block all deliveries to a certain customer for credit reasons. + + + + + Denotes a natural person. + In the following countries, the system needs to know whether the taxpayer is a legal or natural person so that it can check the tax numbers correctly:BrazilBulgariaColombiaCroatiaGreeceItalyMexicoPeruSloveniaThailandUkraineThe flag is also used in conjunction with the Statement of Payments to Natural Persons report, as used in the Czech Republic and in Slovakia. This report only covers customers and vendors for whom you have set this indicator.In South Korea, it is used in conjunction with the Generic Withholding Tax Reporting program. + + + + + Indicates if sales order processing is blocked for the customer in all sales areas (company-wide, for example). + If you block sales order processing, the block counts for the following partner functions of the customer:Sold-to partyShip-to partyPayerIf you want to process an order where the ship-to party differs from the sold-to party, and the ship-to party is blocked, you cannot process the order.You can define different kinds of block, according to the needs of your organization. You can, for example, automatically block all free of charge deliveries and credit memo requests for a certain customer, pending manual approval before further processing can take place. + + + + + Indicates that the account is blocked for posting for all company codes. + If you set this indicator, the system prevents users from posting items to this account and issues an error message to inform them that the account is blocked. + + + + + Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. + + + + + + If the customer or the vendor belongs to a group, you can enter a group key here. The group key is freely assignable. + If you create a matchcode using this group key, group evaluations are possible. + + + + + Account number of another master record in which the official address is stored. This address is used, for example, for tax reports to the tax authorities in Italy. + + + + + + An industry is a distinct group of companies with the same basic business activity. The industry key is used in selecting data for evaluations (for example, a vendor master data list). You can specify industries such as trade, banking, service, manufacturing, health care, public service, media and so on. + The industry field belongs to the general data area of customer and vendor master records. + + + + + Specifies the code that uniquely identifies the industry (or industries) of the customer. + Depending on the standards your organization uses (for example, Standard Industry Codes (SIC)), enter the appropriate code. You can assign more than one industry code to a customer by choosing Create more. + + + + + Specifies an additional code that identifies the industry (or industries) of the customer. + Depending on the standards your organization uses (for example, Standard Industry Codes (SIC)), enter the appropriate code. + + + + + Specifies an additional code that identifies the industry (or industries) of the customer. + Depending on the standards your organization uses (for example, Standard Industry Codes (SIC)), enter the appropriate code. + + + + + Specifies an additional code that identifies the industry (or industries) of the customer. + Depending on the standards your organization uses (for example, Standard Industry Codes (SIC)), enter the appropriate code. + + + + + Specifies an additional code that identifies the industry (or industries) of the customer. + Depending on the standards your organization uses (for example, Standard Industry Codes (SIC)), enter the appropriate code. + + + + + Here you enter the first 7 digits of the international location number. + The International Location Number (ILN) is assigned (in Germany by the Centrale for Coorganisation GmbH)) when a company is founded. It consists of 13 digits, the last digit being the check digit. There are two categories of location numbers:Participants who only need an ILN to cleary and unmistakably identify themselves for communication with the business partner are given a category 1 ILN. This cannot be used to identify articles by means of EAN.Participants who wish to assign the location numbers for their own enterprise areas are given a category 2 ILN. For a category 2 ILN, digits 1 to 7 are described as basis number. This is used as basis for the creation of article numbers (EAN). + + + + + Specifies a regional division according to the market categories created by the A. C. Nielsen company. + By allocating a Nielsen division, you can use the services of the Nielsen Institute to create a market analysis of your customers. + + + + + Classification of companies according to tax aspects. + + + + + + Specifies the tax number. + Enter the appropriate tax number:Country Tax NumberArgentina CUIT number or CUIL numberBelgium Enterprise numberBrazil CNPJ numberBulgaria Unified identification codeChile RUT numberChina VAT registration number (shui wu deng ji hao)Colombia NIT numberCroatia Legal persons: company identification numberNatural persons: JMBG numberCzech Republic DIC numberFrance SIRET numberGreece Personal IDHungary Tax numberItaly Fiscal codeKazakhstan RNN (obsolete)Mexico RFC numberNetherlands SI registration number (Aansluitnummer UWV) of chain- liability vendorNorway VAT numberPeru RUC numberPhilippines Taxpayer identification number (see below)Poland NIP numberPortugal NIF numberRomania Tax numberRussia INNSlovakia DIC numberSlovenia Tax numberSouth Korea Natural persons: Personal identification numberLegal persons: Corporation IDSpain NIF numberSwitzerland UID numberTaiwan - China GUI registration numberThailand Personal IDTurkey Name of business partner's tax officeUkraine Taxpayer identification numberUnited Kingdom Company registration numberUnited States Social security numberVenezuela RIF numberIn the Philippines, enter the taxpayer identification number with a V or N at the end, as follows:If the business partner is liable to VAT: 999-999-999-999VIf the business partner is not liable to VAT: 999-999-999-999N + + + + + Specifies the tax number. + Enter the appropriate tax number:Country Tax NumberArgentina NIP number or CM numberBelgium VAT numberBrazil CPF numberBulgaria Legal persons: tax numberNatural persons: personal IDCroatia OIB number Czech Republic ICO numberFrance SIREN numberGreece AFM numberIndia TINItaly VAT numberKazakhstan BC (Beneficiary Code)Netherlands BSN numberRussia OKPO codeSlovakia ICO numberSouth Korea VAT registration numberSweden Organization registration numberSwitzerland VAT numberTaiwan - China Tax registration numberUkraine Legal persons: USREOU numberNatural persons: SRNP numberTurkey Tax numberUnited Kingdom NI numberUnited States Employer identification numberVenezuela NIT number + + + + + Specifies the tax number. + Enter the tax number that applies:Country Tax numberArgentina Withholding agent numberBrazil State tax numberBulgaria Social security numberMexico CURP numberKazakhstan BINNetherlands Tax registration number (Loonbelastingnummer) of the chain-liability vendorRussia KPP numberThailand Tax ID Ukraine VAT registration number + + + + + Specifies the tax number. + Enter the appropriate tax number:Country Tax NumberBrazil Municipal tax numberKazakhstan IINRussia OFK number (for public bodies only) + + + + + Kazakhstan + Specifies the certificate of registration as VAT payer in the following format: XXXXXYYYYYYYZZZZZZZZ, where: XXXXX is the certificate serial number, YYYYYYY is the certificate number and ZZZZZZZZ is the date of certificate issue. + + + + + Taxes in Argentina: + The format and the check of tax number 1 depend on the two-digit tax number type.The tax number type is an identification type for tax in Argentina (for example, 80 for CUIT) and is used for the DGI tax report. + + + + + VAT registration number (VAT reg.no.) of the customer, vendor or your company code. + The VAT registration number is used within the EU for tax-exempt deliveries for the "EC sales list". The check rules are defined for each EU country and cannot be changed. + + + + + Indicates that all data in this master record is to be deleted. + To delete this data, you have to run the archiving program for Accounts Receivable or Payable. This program will archive all master records marked for deletion provided that there is no dependent data in them.Deletion flags can also be used in the program for deleting master data. You should, however, run this program only to delete test data prior to production startup. + + + + + + + + + + + + + Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. + + + + + + The company code is an organizational unit within financial accounting. + + + + + + Contains settings that control how the system handles differences between the invoice amount and the amount received from a customer or the amount paid to a supplier. A tolerance group is unique within a company code. + + + + + + This field contains the account number the company is listed under at the customer. + + + + + + Identification code for the accounting clerk. + The name of the accounting clerk defined by this identification code can be used in the payment program for correspondence and reporting (for example, open item lists). + + + + + + + + + Account number of the customer for whom automatic payment transactions are to be carried out.The account number is only needed if bank collections are not to be made via the customer who owes the receivables. The same applies to refunds of payables.The specification in this field only applies to this company code. There is another field in which you can enter an alternative payee for all company codes. If both fields are filled, the specification for the company code has priority. + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + Indicator which specifies at what intervals the collective invoices are to be created for the customer. + + + + + + Internal memo of the accounting department. + The memo serves only as information on special features of the customer/vendor. + + + + + This field contains the account number of the head office. + This account number is only specified for branch accounts. All postings for which the account number of the branch is specified, are automatically posted to the head office account. The account number of the branch affected is noted in the line items.No line items or balances are managed in the branch account. + + + + + Indicates that during automatic payment transactions clearing is made with the corresponding vendor account, and that during manual clearing procedures, the items of that vendor account are also selected. + To use this function in automatic payment transactions, you have toenter the vendor account number in the customer master record,enter the customer account number in the vendor master record, andselect the "Clearing with customer" indicator in the vendor master record.If you set this indicator, the system will also include items of the vendor account in customer dunning. + + + + + All bank data is determined using this key. + + + + + + Enter an interest calculation indicator here if the account is to be included in automatic interest calculation. + + + + + + The date in this field displays the last time the interest calculation program processed this account. This is generally the upper limit of the last interest run. + Generally, this date is automatically maintained by the program (batch input). A manual entry in this field should only be made if an error has occurred or when implementing the interest calculation. + + + + + Indicates that payment transactions and dunning notices are created for the branch. + Normally automatic payment transactions and dunning notices are created for the head office.NoteSelect this indicator only if this account is a head office account. + + + + + If this indicator is set, every customer/vendor open item is paid separately during automatic payment transactions. This means that open items are not grouped together for payment. + + + + + + Indicates the layout rule for the Allocation field in the document line item. + The system uses a standard sort sequence for displaying line items. Among other things, it sorts the items according to the content of the Allocation field. This field can be filled either manually or automatically (by the system) when a document line item is entered.For this purpose, the system requires rules that determine which information is to be taken from the document header or from the document line item and placed in the field. The rules can be stored in the master record of an account which enables you to determine the standard sort sequence on an account-specific basis.NoteField information from another document line item cannot be adopted into the field of a particular item. + + + + + Block key (enqueue key) that is used to block an open item or an account to payment transactions. + You can use the block key as described below.Automatic Payment TransactionsIn automatic payment transactions, the block takes effect when it is entered in the system as follows:In the master recordIn the documentIf you enter the block in the master record then all open items for this account are contained in the exception list.The following block keys have a special meaning in the master record:The block key * has the effect that all items of the account are skipped in automatic payment transactions.The block key + has the effect that all items are skipped in which a payment method was not entered explicitly.The block key A is always set automatically when a down payment is entered. Therefore, you must not delete the block key A or use it for other purposes.Whether a block key can be set or removed in payment proposal processing depends on the attribute Changeable in payment proposal of the block key.Manual PaymentsManual payments are only affected by a block key in the document if you set the attribute Blocked for manual payments in the block key.A block key that was set in the master record does not have any effect on manual payments. You can have the system issue a warning message in that case. To do so, you have to make system settings. Set up message 671 of work area F5 in message control accordingly. + + + + + List of payment methods which may be used in automatic payment transactions with this customer/vendor if you do not specify a payment method in the item to be paid. + If you do specify a particular payment method in the item to be paid, this specification has priority over the specifications in the master record. You may also specify payment methods in the item which are not listed in the master record. + + + + + Key for defining payment terms composed of cash discount percentages and payment periods. + It is used in sales orders, purchase orders, and invoices. Terms of payment provide information for:Cash managementDunning proceduresPayment transactionsData can be entered in the field for the terms of payment key in various ways as you enter a business transaction:In most business transactions, the system defaults the key specified in the master record of the customer/vendor in question.In some transactions (for example, credit memos), however, the system does not default the key from the master record. Despite this, you can use the key from the customer/vendor master record by entering "*" in the field.Regardless of whether or not a key is defaulted from the master record, you can manually enter a key during document entry at:item level in sales ordersheader level in purchase orders and invoicesMaster records have separate areas for Financial Accounting, Sales, and Purchasing. You can specify different terms of payment keys in each of these areas. When you then enter a business transaction, the application in question will use the key specified in its area of the master record. + + + + + This indicator specifies that the customer/vendor should be sent all payment advice information by EDI. + + + + + + Indicates that the account is blocked for posting in the specified company code. + If you set this indicator, the system prevents users from posting items to this account and issues an error message to inform them that the account is blocked. + + + + + The reconciliation account in G/L accounting is the account which is updated parallel to the subledger account for normal postings (for example, invoice or payment). + For special postings (for example, down payment or bill of exchange), this account is replaced by another account (for example, 'down payments received' instead of 'receivables').The replacement takes place due to the special G/L indicator which you must specify for these types of postings. + + + + + Indicator that the payment history of the customer is to be recorded. + The amount and number of payments are then recorded per calendar month, as well as the average days in arrears.Information about cash discount payments and net payments is recorded separately.The indicator should not be set for one-time accounts and accounts which are paid automatically (bank collection or bank bill in Germany, bill of exchange payment request in France).You can only carry out evaluation of the payment history, for example, with the report for customer evaluation with OI listing, if you have selected this field. + + + + + Name or identification code of the accounting clerk at the customer. + + + + + + Indicates that the company code data in this master record is to be deleted. + To delete this data, you have to run the archiving program for Accounts Receivable or Payable. This program will archive all master records marked for deletion provided that there is no dependent data in them.This deletion flag cannot be used in the program that deletes master data. You should, however, run this program only to delete test data prior to production startup. + + + + + In cash management, customers and vendors are allocated to planning groups by means of an entry made in the master record. + You can define these planning groups in Customizing or the Implementation Guide (you will need to ensure that they are all the same length). In order to improve the liquidity forecast display for major customers and vendors, it can be advisable to enter their account number as the planning group.For the planning groups themselves a naming convention should be set up to improve liquidity forecasting. In the following examples, the customer planning groups begin with an "R" for receipts, and the vendor planning groups begin with an "E" for expenses.R1 Customers paying by bank collectionR2 Other domestic customersR3 Customers abroadR4 Affiliated company customersR5 High risk customersR6 Major customersR7 Rental incomeR8 Repayment of loans...E1 Domestic vendorsE2 Vendors abroadE3 Affiliated company vendorsE4 Major vendorsE5 Personnel costsE6 TaxesE7 Investments... + + + + + With the key specified here, you can refer to known/negotiated leave. + + + + + + The value adjustment key controls the way the open items are processed during individual value adjustment. + + + + + + The account group is a classifying feature within customer master records. The account group determines: + in which number range the customer account number should be;whether the number is assigned by the user or by the system;which specifications are necessary or possible in the master record. + + + + + + + + + + + + + + Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. + + + + + + The company code is an organizational unit within financial accounting. + + + + + + The dunning area represents an organizational entity that is responsible for dunning. The dunning areas represent a sub-structure of the company codes. + If different responsibilities or different dunning procedures exist within a company code, you can set up corresponding dunning areas.All dunning notices are made separately according to dunning areas, and if necessary with different dunning procedures.The dunning area must be noted in the line items. As long as documents are copied from preliminary work areas (billing documents), the dunning area can be derived from details such as division or sales area, if necessary. + + + + + Key which reflects the reason for a dunning block indicator. + + + + + + Number that specifies how often an item or account has been dunned. + The business partner has received the dunning level from the last dunning run.If you use dunning areas, it is the dunning level that the business partner received from the last dunning run in the dunning area assigned.The dunning program sets the dunning level automatically when the customer or vendor receives a dunning notice. + + + + + This field contains the key for the dunning procedure to be used. + + + + + + Account number of the customer who is to be the recipient of the dunning letters. + The account number is only needed if dunning letters are not sent to the customer who owes the receivables. + + + + + Date on which the last dunning notice was made. + + + + + + Date on which a legal dunning procedure was initiated. + The printing of dunning notices in the legal dunning procedure generates an internal notice about any further account movements. A dunning notice is not created for the customer.If the Legal dunning procedure field in the master record contains a date, this means that the account is involved in a legal dunning procedure. The relationship between this date and the dunning date does not affect how the account is processed.The printing of account movements in the legal dunning procedure differs from the normal printing of dunning notices as follows:You must specify a separate form for your dunning procedure in Customizing. For more information, see Customizing (IMG) under Dunning Forms.The dunning program also displays text element 520 "Legal dunning procedure". This makes it possible to display the date of the legal dunning procedure from the master record.The program also displays the documents blocked for dunning and those with a payment method (automatic debit, bank direct debit).Although dunning notices are printed, the dunning level does not change in the master record or in the items. New dunning level = old dunning level.The program only updates the date of the last dunning run.Enter the date manually. + + + + + Identification code for the accounting clerk dealing with dunning letters. + Using this identification code, the accounting clerk whose name is printed on the dunning letters is determined.If this field is not filled, then the entry from the Accounting clerk field is used. + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + The account group is a classifying feature within customer master records. The account group determines: + in which number range the customer account number should be;whether the number is assigned by the user or by the system;which specifications are necessary or possible in the master record. + + + + + + + + + + + + + Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. + + + + + + An organizational unit responsible for the sale of certain products or services. The responsibility of a sales organization may include legal liability for products and customer claims. + You can assign any number of distribution channels and divisions to a sales organization. A particular combination of sales organization, distribution channel, and division is known as a sales area. + + + + + The way in which products or services reach the customer. Typical examples of distribution channels are wholesale, retail, or direct sales. + You can maintain information about customers and materials by sales organization and distribution channel. Within a sales organization you can deliver goods to a given customer through more than one distribution channel.You can assign a distribution channel to one or more sales organizations. If, for example, you have numerous sales organizations, each sales organization may use the "Wholesale" distribution channel.For each combination of sales organization and distribution channel, you can further assign one or more of the divisions that are defined for the sales organization. You can, for example, assign "Food" and "Non-food" divisions to the "Wholesale" distribution channel. A particular combination of sales organization, distribution channel, and division is known as a sales area. + + + + + A way of grouping materials, products, or services. The system uses divisions to determine the sales areas and the business areas for a material, product, or service. + A product or service is always assigned to just one division. From the point of view of sales and distribution, the use of divisions lets you organize your sales structure around groups of similar products or product lines. This allows the people in a division who process orders and service customers to specialize within a manageable area of expertise.If a sales organization sells food and non-food products through both retail and wholesaledistribution channels each distribution channel could then be further split into food and non-food divisions. + + + + + This field contains the account number your company is listed under at the customer or vendor. + + + + + + The authorization group enables you protect access to certain objects. + In order to carry out a specific activity, the user must have authorization for the combination of the activity and the authorization group. + + + + + Indicates if further billing activities are blocked for the customer. The block applies throughout the specified sales area. + If you enter a blocking indicator, billing that is already underway is continued. However, you cannot process the document further.Enter one of the values predefined for your system. If you want to block billing for a customer throughout an entire sales organization, you must enter a blocking indicator for each sales area in which the sales organization is defined.You can block billing for a customer if, for example, there are credit-related or legal problems to be resolved. + + + + + Indicates whether a sales order must be delivered completely in a single delivery or whether the order can be partially delivered and completed over a number of deliveries. + + + + + + Customer's currency for a sales area. This currency will be used to settle the customer's charges for the given sales organization. + + + + + + + The account assignment group to which the system automatically posts the sales document. + The system uses the account assignment group as one of the criteria during the automatic determination of revenue accounts.The system automatically proposes the account assignment group from the customer master record of the payer. You can change the default value in the sales document or the billing document. + + + + + Identifies a particular group of customers (for example, wholesale or retail) for the purpose of pricing or generating statistics. + + + + + + Key for defining payment terms composed of cash discount percentages and payment periods. + It is used in sales orders, purchase orders, and invoices. Terms of payment provide information for:Cash managementDunning proceduresPayment transactionsData can be entered in the field for the terms of payment key in various ways as you enter a business transaction:In most business transactions, the system defaults the key specified in the master record of the customer/vendor in question.In some transactions (for example, credit memos), however, the system does not default the key from the master record. Despite this, you can use the key from the customer/vendor master record by entering "*" in the field.Regardless of whether or not a key is defaulted from the master record, you can manually enter a key during document entry at:item level in sales ordersheader level in purchase orders and invoicesMaster records have separate areas for Financial Accounting, Sales, and Purchasing. You can specify different terms of payment keys in each of these areas. When you then enter a business transaction, the application in question will use the key specified in its area of the master record. + + + + + A grouping of customers who share the same pricing requirements. + You can define price groups according to the needs of your organization and create pricing records for each group. You can, for example, define a group of customers to whom you want to give the same kind of discount. You can assign a price group to an individual customer either in the customer master record or in the sales document.The system can propose the price group from the customer master record. You can change the proposed value manually in the sales document at both header and item level. + + + + + Determines which pricing procedure the system should apply when you create a sales document for the customer. + You can define different pricing procedures for your system. A pricing procedure determines the type and sequence of conditions that the system uses for pricing in, for example, a sales order. + + + + + Indicates if further delivery processing is blocked for the customer. The block applies throughout the specified sales area. + If you enter a blocking indicator, delivery processing that is already underway is continued. However, no new processing can take place.Enter one of the values predefined for your system. If you want to block delivery processing for a customer within a particular sales organization, you must enter a blocking indicator for each sales area in which the sales organization is defined.You can block delivery processing for a customer if, for example, there are credit-related or legal problems to be resolved. + + + + + The delivery priority assigned to an item. + You can assign delivery priority to either a particular material or to a combination of customer and material. When you process deliveries collectively, you can use delivery priority as one of the selection criteria. + + + + + Commonly used trading terms that comply with the standards established by the International Chamber of Commerce (ICC). + Incoterms specify internationally recognized procedures that the shipper and the receiving party must follow for the shipping transaction to be completed successfully.If goods are shipped through a port of departure, the appropriate Incoterm might be: FOB ("Free On Board"). You can provide further details (for example, the name of the port) in the secondary Incoterm field: FOB Boston, for example. + + + + + Provides additional information for the Incoterms. This field is only available for C-Clauses (if customized appropriately). Note the following for the incoterms versions below: + No Version:This field is disabledIncoterm Version 2000This field is disabled as part of standard delivery unless a customer decides to enable it by the way of Customizing for Sales and Distribution under Master Data -> Business Partners -> Customers -> Billing Document -> Incoterms -> Map Incoterms to Versions.Incoterm Version 2010For this version, the field represents:Sea and inland waterway transport - Port of DestinationAny mode of transport - Place of Destination2010 Incoterms are divided as follows:Group 1: Rules for any mode or modes of transport (including by vessel)Incoterms Incoterms Description Location 2CPT Carriage Paid To Place of DestinationCIP Carriage & Insurance Paid To Place of DestinationGroup 2: Rules for sea and inland waterwaysIncoterms Incoterms Description Location 2CFR Cost & Freight Port of DestinationCIF Cost Insurance & Freight Port of Destination + + + + + An incoterms version is an edition containing a list of international terms for transportation that is defined by the International Chamber of Commerce (ICC). + + + + + + Provides additional information for the primary Incoterm. For Incoterms 2010, this field represents: + 1. For sea and inland waterway transport - Port of Shipment2. For any mode of transport - Place of Delivery 2010Incoterms are divided as follows:Group 1: Rules for any mode or modes of transport (including by vessel)Incoterms Incoterms Description Location 1 EXW Ex Works Place of DeliveryFCA Free Carrier Place of DeliveryCPT Carriage Paid To Place of DestinationCIP Carriage & Insurance Paid To Place of DestinationDAF Delivered at Frontier Place of DeliveryDDP Delivered Duty Paid Place of DestinationDDU Delivered Duty Unpaid Place of DestinationGroup 2: Rules for sea and inland waterwaysIncoterms Incoterms Description Location 1 FAS Free Alongside Ship Port of ShipmentFOB Free On Board Port of ShipmentCFR Cost & Freight Port of DestinationCIF Cost Insurance & Freight Port of DestinationDEQ Delivered Eq Quay (Duty Paid) Port of DestinationDES Delivered Ex Ship Port of DestinationIf the primary incoterm is specified as FOB “Free on Board”, the second field provides details of the port from which the delivery leaves, such as FOB Boston. + + + + + Indicates that all data in the master record will be deleted for the specified sales area. Before the deletion is made, the system checks for dependent data that would prevent the deletion. + + + + + + Additional information for the primary Incoterm. + If the primary Incoterm is, for example, FOB ("Free on Board"), then the second field provides details of the port from which the delivery leaves (for example, "FOB Boston"). + + + + + Identifies the calendar that determines the schedule of billing dates for the customer. + If, for example, a customer wants to consolidate the invoices you send out, you can predefine the billing schedule in a calendar in the system. During billing, the system automatically proposes the appropriate billing date from the calendar.The system proposes the billing schedule from the customer master record of the payer. You can change the value manually in the sales document. + + + + + The probability (expressed as a percentage) of the customer confirming the inquiry or quotation item as part of a sales order. + The system combines the probability factors from the sales document type and from the customer master record of the sold-to party.If probability is 80% for the sales document type and 50% in the customer master record, the system combines the two values. In this case, the system takes 50% of 80% and proposes 40% for the item.The system proposes the probability. You can change the value manually for the item.You can generate requirements from quotations. Accordingly, the probability of quotation items affects how requirements are passed on. For example, a quotation for 100 pieces and a probability of 50% will generate requirements for 50 pieces. + + + + + Indicates whether you are allowed to combine orders during delivery processing. + The system proposes the indicator from the customer master record. You can change the value manually in the sales document at both header and item level. + + + + + Indicates if further sales order processing is blocked for the customer. The block applies throughout the specified sales area. + You can define blocks according to the needs of your organization. If you enter a blocking indicator, sales order processing that is already underway is continued. However, no new processing can occur.Enter one of the values predefined for your system. If you want to block sales order processing for a customer within a particular sales organization, you must enter a blocking indicator for each sales area in which the sale organization is defined.You can block sales order processing for a customer if, for example, there are credit-related or legal problems to be resolved. + + + + + Specifies whether the customer requires full or partial delivery for the item. + You use this field to control partial deliveries at the item level. If the customer allows partial delivery, you can choose from different partial delivery options. For example, you can specify whether the customer allows you to make one delivery attempt only on the requested delivery date or whether unlimited delivery attempts are possible.When partial delivery indicator 'D' is set, the order can never have status 'fully delivered'. You must complete each item by entering a reason for rejection. This could be applied to scheduling agreements, for example.You can enter a value in this field only if the customer allows partial deliveries for the entire sales document. + + + + + Identifies a price list or other condition type (for example, a surcharge or discount). + You can define price list types according to the needs of your own organization. Price list types can be grouped according to:the kind of price list (for example, wholesale or retail)the currency in which the price appearsthe number of the price list typeYou can use price list types to apply conditions during pricing or to generate statistics.In the customer master record, enter one of the values predefined for your system. The system proposes the value automatically during sales order processing. You can change the value manually in the sales document header. + + + + + A group of sales people who are responsible for processing sales of certain products or services. + By using sales groups you can designate different areas of responsibility within a sales office. When you generate sales statistics, you can use the sales group as one of the selection criteria.If sales office personnel service both retail and wholesale markets, you can assign a sales group to each market.You assign each salesperson to a sales group in his or her user master record. You assign each customer to a particular sales group in the customer's master record. + + + + + A physical location (for example, a branch office) that has responsibility for the sale of certain products or services within a given geographical area. + When you create sales statistics, you can use a sales office as one of the selection criteria. When you print out order confirmations, you can include the address of the sales office.You can assign each customer to a sales office in the customer master record.Within a sales office you can establish sales groups (for example, departments) with specific sales responsibilities. Each person who works in the sales office can be assigned to a sales group in his or her user master record. Each customer can also be assigned to a particular sales group in the customer master record. + + + + + General shipping strategy for the delivery of goods from the vendor to the customer. + You can define shipping conditions in your system which correspond to the requirements of your company. You can specify a shipping condition in the customer master and in the vendor master.Shipping point determination (outbound delivery):The loading group, the plant and the shipping condition determine the shipping point that will be proposed by the system.Route determination (outbound delivery):Apart from the country and the geographical region of the shipping point, the ship-to party and the transportation group, the shipping condition determines the route that the system proposes in the order for the delivery of the goods. In the delivery, the route proposal also takes the weight group into account.A particular customer always requires immediate delivery. You enter the appropriate shipping condition into the customer master record. This means that when you process orders for this customer, the system automatically proposes the express mail room as a shipping point and the quickest way to the airport as a route.If a shipping condition has been assigned to a sales document type in Customizing, this condition will be proposed by the system in the corresponding sales document. If there is no assignment, the system copies the relevant data from the corresponding customer master record of the sold-to party. You cannot change this value during delivery processing. The shipping condition will not be copied from the delivery into the shipment. The shipping condition is one of several criteria for selecting deliveries when you create a shipment. You can enter a shipping condition manually in the shipment where it only serves as a characteristic for grouping shipments. + + + + + Plant from which the goods should be delivered to the customer. + This plant is automatically copied into the sales order item as the default value.If there is no default value when you process the sales order item, enter a delivering plant.The value proposed in the item is eitherfrom the customer master record of the goods recipient, orfrom the material master recordThe system checks whether it can propose a value (and for your own plants, whether the material has been created in the plant). If the system can propose a value, the plant is copied to the sales order item where you can change it as required. + + + + + A geographical sales district or region. + Each customer can be assigned to a sales district. You can use sales districts to apply pricing conditions. When you want to generate sales statistics, you can use sales districts as a selection criteria.The system can propose a value from the customer master record of the sold-to party. You can change the value manually in the document at the header or item level. + + + + + Identifies the customer's factory calendar that is used during the processing of invoice lists. + An invoice list is a list of invoices (single or collective) that you create for the customer either periodically or on predefined dates. The periods and dates are defined in the customer's factory calendar. Typically, the recipient of an invoice list takes on the responsibility for collecting payments from numerous individual customers and receives a factoring or del credere discount for the service.If you want to create invoice lists for the customer, you must enter an identifier for a predefined factory calendar. + + + + + Key representing a type of exchange rate in the system. + You enter the exchange rate type to store different exchange rates.You can use the exchange rate type to define a buying rate, selling rate, or average rate for translating foreign currency amounts. You can use the average rate for the currency translation, and the bank buying and selling rates for valuation of foreign currency amounts. + + + + + Specifies a customer-defined group of customers. + You can define up to five different groups of customers, according to the needs of your organization. You specify the groups in the customer master record under "Additional data". If you assign a particular customer to one or more groups, the system automatically displays the groups in the header data of corresponding sales orders.You can define customer groups in Tables TVV1 through TVV5 and assign them to specific languages in Tables TVV1T through TVV5T. + + + + + Specifies a customer-defined group of customers. + You can define up to five different groups of customers, according to the needs of your organization. You specify the groups in the customer master record under "Additional data". If you assign a particular customer to one or more groups, the system automatically displays the groups in the header data of corresponding sales orders.You can define customer groups in Tables TVV1 through TVV5 and assign them to specific languages in Tables TVV1T through TVV5T. + + + + + Specifies a customer-defined group of customers. + You can define up to five different groups of customers, according to the needs of your organization. You specify the groups in the customer master record under "Additional data". If you assign a particular customer to one or more groups, the system automatically displays the groups in the header data of corresponding sales orders.You can define customer groups in Tables TVV1 through TVV5 and assign them to specific languages in Tables TVV1T through TVV5T. + + + + + Specifies a customer-defined group of customers. + You can define up to five different groups of customers, according to the needs of your organization. You specify the groups in the customer master record under "Additional data". If you assign a particular customer to one or more groups, the system automatically displays the groups in the header data of corresponding sales orders.You can define customer groups in Tables TVV1 through TVV5 and assign them to specific languages in Tables TVV1T through TVV5T. + + + + + Specifies a customer-defined group of customers. + You can define up to five different groups of customers, according to the needs of your organization. You specify the groups in the customer master record under "Additional data". If you assign a particular customer to one or more groups, the system automatically displays the groups in the header data of corresponding sales orders.You can define customer groups in Tables TVV1 through TVV5 and assign them to specific languages in Tables TVV1T through TVV5T. + + + + + This key identifies the customer payment guarantee procedure. + The customer payment guarantee procedure determines which payment guarantee procedure the system automatically uses when you create a sales document for the customer.In receivables risk management, the system determines the payment guarantee procedure taking into account:the key for the document payment guarantee procedure in the header for the sales document type.the customer payment guarantee procedure key in the customer master.You can define different payment guarantee procedures for your system. The payment guarantee procedure defines the type and sequence of forms of payment guarantee that the system assigns to the sales document items. + + + + + The account group is a classifying feature within customer master records. The account group determines: + in which number range the customer account number should be;whether the number is assigned by the user or by the system;which specifications are necessary or possible in the master record. + + + + + + + + + + + + + + + + + Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. + + + + + + An organizational unit responsible for the sale of certain products or services. The responsibility of a sales organization may include legal liability for products and customer claims. + You can assign any number of distribution channels and divisions to a sales organization. A particular combination of sales organization, distribution channel, and division is known as a sales area. + + + + + Specifies a distribution channel that you want to use as a reference for customer and material master data for other distribution channels. + You can specify one distribution channel as the source of customer and material master data for other distribution channels. You need then only to maintain the data in one place.Distrib.channel Ref.distrib.channel01 0102 0103 0104 04In this example, only distribution channels 01 and 04 have customer and material master data defined. Distribution channels 01, 02, and 03 share the master data that you defined for distribution channel 01. Distribution channel 04 has its own master data. When you create a sales order in distribution channel 03, the system checks the customer and material master data against the data defined for distribution channel 01. + + + + + A way of grouping materials, products, or services. The system uses divisions to determine the sales areas and the business areas for a material, product, or service. + A product or service is always assigned to just one division. From the point of view of sales and distribution, the use of divisions lets you organize your sales structure around groups of similar products or product lines. This allows the people in a division who process orders and service customers to specialize within a manageable area of expertise.If a sales organization sells food and non-food products through both retail and wholesaledistribution channels each distribution channel could then be further split into food and non-food divisions. + + + + + Identifies the country in which the delivery originates. + You can define the country key in a table. As a rule, it is a good idea to use the existing international standards for identifying vehicles from different countries (for example: USA = United States, I = Italy, and so on). The system uses the key tohelp determine the relevant taxes during pricingdetermine important country-specific standards (the length of postal codes and bank account numbers, for example) + + + + + Identifies the condition that the system uses to automatically determine country-specific taxes during pricing. + You can define one or more tax categories for each country. During sales order processing, the system applies the tax category according tothe geographical location of your delivering plant and the location of the customer receiving the goodstax classifications in the customer master record and the material master record.In the USA, for example, you can define tax categories for Federal Sales Tax and Federal Excise Tax. In the U.K., you can define a tax category for Value Added Tax (VAT). + + + + + Specifies the tax liability of the customer, based on the tax structure of the customer's country. + You can use the tax classification to specify, for example, whether a customer is liable for sales taxes, such as VAT or state sales taxes.During sales order processing, the system copies the tax classification from the tax information stored in thecustomer master record of the payer, if the payer is different from the sold-to party and the sales tax identification number is maintained for the payer.ship to party, if the sales tax identification number of the ship-to party is maintained.sold-to party, if none of the criteria for the payer or the ship-to party are met.During pricing, the system calculates any relevant taxes by taking the following factors into account:The tax classification of the customer and the materialThe country keys of the customer and the delivering plant + + + + + + + + + + + + Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. + + + + + + The company code is an organizational unit within financial accounting. + + + + + + This indicator is used to classify the different types of withholding tax. + Withholding tax types classify particular features of a withholding tax including:The time at which the withholding tax is postedThe basis on which the base amount is calculatedThe basis for accumulation (if applicable)Withholding tax types are to be distinguished from withholding tax codes, to which are allocated the withholding tax percentage rate example.Whether a withholding tax can be defined as an existing type by means of a new code, or if a new type needs to be defined will depend on the type of transaction (see below).Note that a business transaction can only be assigned one withholding tax code per withholding tax type. If the business transaction is subject to several withholding taxes simultaneously, these must be represented by different types.This is the case in Argentina for example, where up to four kinds of withholding tax per business transaction are possible. + + + + + One or more "withholding tax codes" are assigned to each withholding tax type. One of the things these codes determine is the various percentage rates for the withholding tax type. + Note that when processing a business transaction, no more than one withholding tax code can be assigned per withholding tax type. If the business transaction is subject to more than one withholding taxes, these must be represented in the system by defining various withholding tax types. + + + + + + Date from which: + The company code is obligated to withhold tax for the given withholding tax type.This date must be entered in Customizing under the withholding tax information for the company code.The customer is obligated to withhold tax for the withholding tax type.This date must be defined in the customer master record. + + + + + Date to which: + The company code is obligated to withhold tax for the withholding tax type.This date must be entered in Customizing under the withholding tax information for the company code.The customer is obigated to withhold tax for the withholding tax type. + + + + + This is a number issued by the tax authorities per withholding tax type. + This number must be specified in Customizing either:(a) As part of the withholding tax information defined for the company code, or(b) As part of the withholding tax information defined in the customer or vendor master record. + + + + + Numbered assigned by the relevant authorities for exemption from withholding tax. + This number must be entered in the system as follows:In the vendor master record in the case of vendorsFor customers, in Customizing under the settings for withholding tax information for the company code per withholding tax type. + + + + + Rate of exemption from withholding tax. + Those persons/activities subject to withholding tax can be exempted from withholding tax up to the percentage rate you enter here. This exemption rate refers to the withholding tax amount itself and not to the whole amount liable to withholding tax (withholding tax base amount).The gross amount of an invoice is 100.00 and the withholding tax base amount is defined as gross. The withholding tax rate is 10% meaning that the withholding tax amount is 10.00. Given an exemption rate of 30%, the withholding tax amount is reduced to 7.00. + + + + + Date from which withholding tax exemption applies. + + + + + + Date on which withholding tax exemption expires. + + + + + + Indicator used to classify different types of exemption from liability to a particular withholding tax. + These indicators can be defined per withholding tax type in the vendor master record. + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + + + + + + + + + + + Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. + + + + + + An organizational unit responsible for the sale of certain products or services. The responsibility of a sales organization may include legal liability for products and customer claims. + You can assign any number of distribution channels and divisions to a sales organization. A particular combination of sales organization, distribution channel, and division is known as a sales area. + + + + + The way in which products or services reach the customer. Typical examples of distribution channels are wholesale, retail, or direct sales. + You can maintain information about customers and materials by sales organization and distribution channel. Within a sales organization you can deliver goods to a given customer through more than one distribution channel.You can assign a distribution channel to one or more sales organizations. If, for example, you have numerous sales organizations, each sales organization may use the "Wholesale" distribution channel.For each combination of sales organization and distribution channel, you can further assign one or more of the divisions that are defined for the sales organization. You can, for example, assign "Food" and "Non-food" divisions to the "Wholesale" distribution channel. A particular combination of sales organization, distribution channel, and division is known as a sales area. + + + + + A way of grouping materials, products, or services. The system uses divisions to determine the sales areas and the business areas for a material, product, or service. + A product or service is always assigned to just one division. From the point of view of sales and distribution, the use of divisions lets you organize your sales structure around groups of similar products or product lines. This allows the people in a division who process orders and service customers to specialize within a manageable area of expertise.If a sales organization sells food and non-food products through both retail and wholesaledistribution channels each distribution channel could then be further split into food and non-food divisions. + + + + + The sequential number that the system applies when there is more than one partner for a particular partner function. + When you create a sales order for a particular customer, there may be more than one ship-to party defined. The different ship-to parties are numbered sequentially. + + + + + The abbreviated form of the name that identifies the partner function. + + + + + + + Sold-to party number sent in by the customer in delivery schedules. + The system uses this number to automatically determine the ship-to party. + + + + + Specifies a partner as the default for a particular partner function. + When you enter more than one partner for a particular partner function (for example, you define three different ship-to parties), you can select one partner as the default. During sales or purchasing processing, if you have defined multiple partners for a partner function, the system prompts you to choose just one partner. The system presents the default partner as the first choice in the pop-up window. + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + + + + + + Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. + + + + + + The account number of the vendor with whom automatic payment transactions are carried out. + The field is only needed if payments are not to be made directly to the vendor to whom the payable is owed. The same applies to bank collections of receivables.The specification in this field applies to all company codes. There is a further field in which every company code can enter an alternative payee separately. If both fields are filled, the company code specification has priority. + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + Name with which the user who entered the master record was logged on in the R/3 System. + + + + + + Date on which the master record, or the part of the master record being viewed, was created. + + + + + + Gives an alphanumeric key, which clearly identifies the customer or vendor in the SAP system. + + + + + + + Indicates that the account is blocked for posting for all company codes. + If you set this indicator, the system prevents users from posting items to this account and issues an error message to inform them that the account is blocked. + + + + + Indicates whether or not the supplier master record is blocked for all departments (that is, whether or not posting to this record is allowed at all). + + + + + + The account group is a classifying feature within vendor master records. The account group determines: + the number interval for the account number of the vendor,whether the number is assigned by the user or by the system,which specifications are necessary and/or possible in the master record. + + + + + + + VAT registration number (VAT reg.no.) of the customer, vendor or your company code. + The VAT registration number is used within the EU for tax-exempt deliveries for the "EC sales list". The check rules are defined for each EU country and cannot be changed. + + + + + + + Indicates that all data in this master record is to be deleted. + To delete this data, you have to run the archiving program for Accounts Receivable or Payable. This program will archive all master records marked for deletion provided that there is no dependent data in them.Deletion flags can also be used in the program for deleting master data. You should, however, run this program only to delete test data prior to production startup. + + + + + Specifies an additional master record in which the official address is stored. + This address is used in Italy for business transactions with the tax office in Italy. + + + + + An industry is a distinct group of companies with the same basic business activity. The industry key is used in selecting data for evaluations (for example, a vendor master data list). You can specify industries such as trade, banking, service, manufacturing, health care, public service, media and so on. + The industry field belongs to the general data area of customer and vendor master records. + + + + + Here you enter the first 7 digits of the international location number. + The International Location Number (ILN) is assigned (in Germany by the Centrale for Coorganisation GmbH)) when a company is founded. It consists of 13 digits, the last digit being the check digit. There are two categories of location numbers:Participants who only need an ILN to cleary and unmistakably identify themselves for communication with the business partner are given a category 1 ILN. This cannot be used to identify articles by means of EAN.Participants who wish to assign the location numbers for their own enterprise areas are given a category 2 ILN. For a category 2 ILN, digits 1 to 7 are described as basis number. This is used as basis for the creation of article numbers (EAN). + + + + + Here, you enter digits 8-12 of the 13-digit international location number. + The international location number (ILN) is assigned when establishing a company (by the "Zentrale für Coorganisation GmbH" in Germany). It consists of 13 digits, the last of which is the check digit. There are two types of international location numbers:Subscribers who only need one ILN to identify themselves in communication with the business partner are given an ILN of type 1. These cannot be used for identifying articles by means of EAN.Subscribers who need to assign location numbers for their own company areas are given an ILN of type 2. Positions 1 through 7 of the ILN type 2 are known as the basis number. This basis number forms the basis for article numbers (EAN). + + + + + The check digit is derived from a special check digit procedure from digits of the previous international location numbers. In this way, you can check whether the ILN entered is actually valid. + + + + + + Denotes a natural person. + In the following countries, the system needs to know whether the taxpayer is a legal or natural person so that it can check the tax numbers correctly:BrazilBulgariaColombiaCroatiaGreeceItalyMexicoPeruSloveniaThailandUkraineThe flag is also used in conjunction with the Statement of Payments to Natural Persons report, as used in the Czech Republic and in Slovakia. This report only covers customers and vendors for whom you have set this indicator.In South Korea, it is used in conjunction with the Generic Withholding Tax Reporting program. + + + + + Classification of companies according to tax aspects. + + + + + + Date up to which the certification of the QM-system is valid. + + + + + + If a QM system is maintained by the supplier, you can store a description of the QM system here. + If a material is activated for QM in procurement, the system initiates the following check whenever purchasing functions are carried out (for example, when a request for a quotation is made or if a purchase order is created):Whether the supplier's verified QM system, according to supplier master record or quality info-record (for a combination of supplier/material) meets the requirements for QM systems as specified in the material masterIn carrying out the check, the system relies on the defined assignments for target QM systems and actual QM systems in the Customizing application.If the check is unsuccessful, a warning message is issued when a request for quotation is initiated and an error message is issued for all other procurement activities. + + + + + If the customer or the vendor belongs to a group, you can enter a group key here. The group key is freely assignable. + If you create a matchcode using this group key, group evaluations are possible. + + + + + Key that determines which procurement functions (for example, request for quotation, purchase order, or goods receipt) should be blocked for quality reasons. + You can enter a block key in the:Supplier master recordIn this case, the supplier block applies to all materials and plants.Quality info record for QM in procurementIn this case, the supplier block applies to a single material and plant.A block for quality reasons applies only to those materials for which QM in procurement is active. + + + + + Specifies the tax number. + Enter the appropriate tax number:Country Tax NumberArgentina CUIT number or CUIL numberBelgium Enterprise numberBrazil CNPJ numberBulgaria Unified identification codeChile RUT numberChina VAT registration number (shui wu deng ji hao)Colombia NIT numberCroatia Legal persons: company identification numberNatural persons: JMBG numberCzech Republic DIC numberFrance SIRET numberGreece Personal IDHungary Tax numberItaly Fiscal codeKazakhstan RNN (obsolete)Mexico RFC numberNetherlands SI registration number (Aansluitnummer UWV) of chain- liability vendorNorway VAT numberPeru RUC numberPhilippines Taxpayer identification number (see below)Poland NIP numberPortugal NIF numberRomania Tax numberRussia INNSlovakia DIC numberSlovenia Tax numberSouth Korea Natural persons: Personal identification numberLegal persons: Corporation IDSpain NIF numberSwitzerland UID numberTaiwan - China GUI registration numberThailand Personal IDTurkey Name of business partner's tax officeUkraine Taxpayer identification numberUnited Kingdom Company registration numberUnited States Social security numberVenezuela RIF numberIn the Philippines, enter the taxpayer identification number with a V or N at the end, as follows:If the business partner is liable to VAT: 999-999-999-999VIf the business partner is not liable to VAT: 999-999-999-999N + + + + + Specifies the tax number. + Enter the appropriate tax number:Country Tax NumberArgentina NIP number or CM numberBelgium VAT numberBrazil CPF numberBulgaria Legal persons: tax numberNatural persons: personal IDCroatia OIB number Czech Republic ICO numberFrance SIREN numberGreece AFM numberIndia TINItaly VAT numberKazakhstan BC (Beneficiary Code)Netherlands BSN numberRussia OKPO codeSlovakia ICO numberSouth Korea VAT registration numberSweden Organization registration numberSwitzerland VAT numberTaiwan - China Tax registration numberUkraine Legal persons: USREOU numberNatural persons: SRNP numberTurkey Tax numberUnited Kingdom NI numberUnited States Employer identification numberVenezuela NIT number + + + + + Specifies the tax number. + Enter the tax number that applies:Country Tax numberArgentina Withholding agent numberBrazil State tax numberBulgaria Social security numberMexico CURP numberKazakhstan BINNetherlands Tax registration number (Loonbelastingnummer) of the chain-liability vendorRussia KPP numberThailand Tax ID Ukraine VAT registration number + + + + + Specifies the tax number. + Enter the appropriate tax number:Country Tax NumberBrazil Municipal tax numberKazakhstan IINRussia OFK number (for public bodies only) + + + + + Kazakhstan + Specifies the certificate of registration as VAT payer in the following format: XXXXXYYYYYYYZZZZZZZZ, where: XXXXX is the certificate serial number, YYYYYYY is the certificate number and ZZZZZZZZ is the date of certificate issue. + + + + + The tax number of the vendor at the responsible tax authority. + + + + + + Taxes in Argentina: + The format and the check of tax number 1 depend on the two-digit tax number type.The tax number type is an identification type for tax in Argentina (for example, 80 for CUIT) and is used for the DGI tax report. + + + + + This indicator controls the process of proof of delivery during the incoming goods process for inbound deliveries. Processing is activating by switching on this indicator in the supplier master and by switching on the corresponding indicator in the delivery item category. + There are the following different characteristics:' ': not relevant for POD'A': generally relevant for POD'B': only relevant for POD if differences(Difference between notified quantity and actual quantity received) + + + + + Tax calculation for Brazil: + The IPI tax value is split up for this vendor. 50% of the calculated IPI tax value is posted as deductible input tax, 50% is deducted from the inventory posting or posting to expense account. + + + + + + + + + + + + + Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. + + + + + + The company code is an organizational unit within financial accounting. + + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + + Block key (enqueue key) that is used to block an open item or an account to payment transactions. + You can use the block key as described below.Automatic Payment TransactionsIn automatic payment transactions, the block takes effect when it is entered in the system as follows:In the master recordIn the documentIf you enter the block in the master record then all open items for this account are contained in the exception list.The following block keys have a special meaning in the master record:The block key * has the effect that all items of the account are skipped in automatic payment transactions.The block key + has the effect that all items are skipped in which a payment method was not entered explicitly.The block key A is always set automatically when a down payment is entered. Therefore, you must not delete the block key A or use it for other purposes.Whether a block key can be set or removed in payment proposal processing depends on the attribute Changeable in payment proposal of the block key.Manual PaymentsManual payments are only affected by a block key in the document if you set the attribute Blocked for manual payments in the block key.A block key that was set in the master record does not have any effect on manual payments. You can have the system issue a warning message in that case. To do so, you have to make system settings. Set up message 671 of work area F5 in message control accordingly. + + + + + Indicates that the account is blocked for posting in the specified company code. + If you set this indicator, the system prevents users from posting items to this account and issues an error message to inform them that the account is blocked. + + + + + Identification code for the accounting clerk. + The name of the accounting clerk defined by this identification code can be used in the payment program for correspondence and reporting (for example, open item lists). + + + + + + + Name or identification code of the accounting clerk at the vendor. + + + + + + + List of payment methods which may be used in automatic payment transactions with this customer/vendor if you do not specify a payment method in the item to be paid. + If you do specify a particular payment method in the item to be paid, this specification has priority over the specifications in the master record. You may also specify payment methods in the item which are not listed in the master record. + + + + + Key for defining payment terms composed of cash discount percentages and payment periods. + It is used in sales orders, purchase orders, and invoices. Terms of payment provide information for:Cash managementDunning proceduresPayment transactionsData can be entered in the field for the terms of payment key in various ways as you enter a business transaction:In most business transactions, the system defaults the key specified in the master record of the customer/vendor in question.In some transactions (for example, credit memos), however, the system does not default the key from the master record. Despite this, you can use the key from the customer/vendor master record by entering "*" in the field.Regardless of whether or not a key is defaulted from the master record, you can manually enter a key during document entry at:item level in sales ordersheader level in purchase orders and invoicesMaster records have separate areas for Financial Accounting, Sales, and Purchasing. You can specify different terms of payment keys in each of these areas. When you then enter a business transaction, the application in question will use the key specified in its area of the master record. + + + + + Indicates that during automatic payment transactions, clearing is made with the corresponding customer account, and that during manual clearing procedures, the items of that customer account are also selected. + To use this function in automatic payment transactions, you have toenter the customer account number in the vendor master record,enter the vendor account number in the customer master record, andselect the "Clearing with vendor" indicator in the customer master record.If this indicator is set, items belonging to the customer account will be included in any dunning run. + + + + + Indicates that payment transactions and dunning notices are created for the branch. + Normally automatic payment transactions and dunning notices are created for the head office.NoteSelect this indicator only if this account is a head office account. + + + + + If this indicator is set, every customer/vendor open item is paid separately during automatic payment transactions. This means that open items are not grouped together for payment. + + + + + + This indicator specifies that the customer/vendor should be sent all payment advice information by EDI. + + + + + + All bank data is determined using this key. + + + + + + Number of days which usually pass until the vendor has cashed your check. + During automatic payment transactions, the system calculates the value date for check payments using this information and stores the date in the line item. The date is calculated as follows:Value date = posting date + check cashing timeIn Cash Management, the value date is used as information about the expected cash outflow. + + + + + Currency key for amounts in the system. + + + + + + Maximum amount which may be issued on a bill of exchange if it is to be used in payment transactions with the business partner. + The amount limit is taken into consideration in automatic payment transactions for payments by bill of exchange and bill of exchange payment requests. Several bill of exchange forms are created if the amount to be settled is higher than the maximum amount given here. Each of these bills of exchange is issued for the maximum amount or for a smaller amount.Amount limits for bills of exchange are used in Spain, for example. + + + + + This field contains the account number the company is listed under at the vendor. + + + + + + The reconciliation account in G/L accounting is the account which is updated parallel to the subledger account for normal postings (for example, invoice or payment). + For special postings (for example, down payment or bill of exchange), this account is replaced by another account (for example, 'down payments received' instead of 'receivables').The replacement takes place due to the special G/L indicator which you must specify for these types of postings. + + + + + Enter an interest calculation indicator here if the account is to be included in automatic interest calculation. + + + + + + The date in this field displays the last time the interest calculation program processed this account. This is generally the upper limit of the last interest run. + Generally, this date is automatically maintained by the program (batch input). A manual entry in this field should only be made if an error has occurred or when implementing the interest calculation. + + + + + This field contains the account number of the master record for the head office account. + You specify this account number only for branch accounts. Items that you post using the branch account number are automatically posted to the head office account. The system records the branch account number in the line items.Neither transactions nor balances are kept in the branch account. + + + + + The account number of the vendor with whom automatic payment transactions are to be carried out. + The field is only needed if payments are not to be made directly to the vendor to whom the payable is owed. The same applies to bank collections of receivables.The specification in this field applies only to the company code. There is a further field in which you can enter an alternative payee for each company code. If both fields are filled, the company code specified has priority. + + + + + Indicates the layout rule for the Allocation field in the document line item. + The system uses a standard sort sequence for displaying line items. Among other things, it sorts the items according to the content of the Allocation field. This field can be filled either manually or automatically (by the system) when a document line item is entered.For this purpose, the system requires rules that determine which information is to be taken from the document header or from the document line item and placed in the field. The rules can be stored in the master record of an account which enables you to determine the standard sort sequence on an account-specific basis.NoteField information from another document line item cannot be adopted into the field of a particular item. + + + + + Contains settings that control how the system handles differences between the invoice amount and the amount received from a customer or the amount paid to a supplier. A tolerance group is unique within a company code. + + + + + + US government requirement. + Date field in which to enter certification date for small companies run by women or minorities. This certificate must be renewed every two years. + + + + + Internal memo of the accounting department. + The memo serves only as information on special features of the customer/vendor. + + + + + In some countries, an additional country is needed for calculating or reporting withholding tax. + The calculation can depend on the payee's country.A particular country key can be required by law for reporting which may possibly be different to the key used in the address.Examples: Japan, USA (1042), Argentina + + + + + Indicates that the company code data in this master record is to be deleted. + To delete this data, you have to run the archiving program for Accounts Receivable or Payable. This program will archive all master records marked for deletion provided that there is no dependent data in them.This deletion flag cannot be used in the program that deletes master data. You should, however, run this program only to delete test data prior to production startup. + + + + + In cash management, customers and vendors are allocated to planning groups by means of an entry made in the master record. + You can define these planning groups in Customizing or the Implementation Guide (you will need to ensure that they are all the same length). In order to improve the liquidity forecast display for major customers and vendors, it can be advisable to enter their account number as the planning group.For the planning groups themselves a naming convention should be set up to improve liquidity forecasting. In the following examples, the customer planning groups begin with an "R" for receipts, and the vendor planning groups begin with an "E" for expenses.R1 Customers paying by bank collectionR2 Other domestic customersR3 Customers abroadR4 Affiliated company customersR5 High risk customersR6 Major customersR7 Rental incomeR8 Repayment of loans...E1 Domestic vendorsE2 Vendors abroadE3 Affiliated company vendorsE4 Major vendorsE5 Personnel costsE6 TaxesE7 Investments... + + + + + When incoming invoices are entered or when memos are entered in Financial Accounting (FI), the system checks whether an invoice or credit memo has already been entered for the same date. + Checking Logistics DocumentsThe system checks whether the invoice documents have already been entered in the Logistics invoice verification. For this, the system checks invoices that have been held or parked or that contain errors, or invoices that were entered for invoice verification in the background. The check is performed only if you specify the reference document number when you enter the invoices.When checking for duplicate invoices, the system compares the following specified characteristics:VendorCurrencyCompany CodeGross Invoice AmountReference Document NumberInvoice Document DateIf all of these characteristics are the same, the system issues a message for which you can change the message type in Customizing.When you enter credit memos or subsequent adjustments, the system does not check for duplicate invoices.Exception: The exception is the Argentina country version, where the system checks for duplicate invoices and credit memos.No message is issued if you enter a document that has previously been reversed.In Customizing for Logistics Invoice Verification under Incoming Invoice -> Set Check for Duplicate Invoices, you can specify that the following characteristics are not checked:Reference Document NumberInvoice Document DateCompany CodeHaving fewer attributes to check increases the likelihood that the system will find a duplicate invoice.Example:The following document has already been entered and posted:Reference Document Number 333Invoice Date: 4/28/2000Gross Invoice Amount 100.00Currency: EURVendor: SpencerCompany Code: ChicagoYou have set up the check for duplicate invoices as follows in Customizing:The characteristics Reference Document Number and Company Code are not activated. Consequently, these characteristics are not checked.Now you enter the following invoice:Reference Document Number 334Invoice Date: 4/28/2000Gross Invoice Amount 100.00Currency: EURVendor: SpencerCompany Code: FlagstaffResultBecause you entered a reference document when you entered the invoice, the system checks for duplicate invoices. Compared against the invoice entered earlier, the invoice just entered has different values in the characteristics Reference and Company Code. However, these characteristics are not checked due to the settings that you have made in Customizing. All other characteristics are the same. The system issues a message telling you that an invoice has been entered twice.If the characteristic "Reference Document Number" had been selected in Customizing, the system would have checked the reference document number and established that it was different from the invoice entered earlier, and it consequently would not have issued a message.Checking FI DocumentsThe system checks whether there are FI documents that were posted or parked with the Logistics invoice verification or with an FI invoice transaction. Depending on the entry in the Reference field, one of the following checks is performed:If a reference number was specified in the sequential invoice/credit memo, the system checks whether an invoice/credit memo has already been posted for which all the following attributes agree:Company CodeVendorCurrencyDocument DateReference NumberIf no reference number was specified in the sequential invoice/credit memo, the system checks whether an invoice/credit memo has already been posted for which all the following attributes agree:Company CodeVendorCurrencyDocument DateAmount in Document CurrencyIn Materials Management, the system applies the check for duplicate invoices for invoices only, not for credit memos. + + + + + + The account group is a classifying feature within vendor master records. The account group determines: + the number interval for the account number of the vendor,whether the number is assigned by the user or by the system,which specifications are necessary and/or possible in the master record. + + + + + + + + + + + + + + Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. + + + + + + The company code is an organizational unit within financial accounting. + + + + + + The dunning area represents an organizational entity that is responsible for dunning. The dunning areas represent a sub-structure of the company codes. + If different responsibilities or different dunning procedures exist within a company code, you can set up corresponding dunning areas.All dunning notices are made separately according to dunning areas, and if necessary with different dunning procedures.The dunning area must be noted in the line items. As long as documents are copied from preliminary work areas (billing documents), the dunning area can be derived from details such as division or sales area, if necessary. + + + + + Key which reflects the reason for a dunning block indicator. + + + + + + Number that specifies how often an item or account has been dunned. + The business partner has received the dunning level from the last dunning run.If you use dunning areas, it is the dunning level that the business partner received from the last dunning run in the dunning area assigned.The dunning program sets the dunning level automatically when the customer or vendor receives a dunning notice. + + + + + This field contains the key for the dunning procedure to be used. + + + + + + Account number of the vendor who is to receive the dunning notice. + Note:If an entry is not made in this field, the dunning notice is sent to the address of the vendor to be processed. + + + + + Date on which the last dunning notice was made. + + + + + + Date on which a legal dunning procedure was initiated. + The printing of dunning notices in the legal dunning procedure generates an internal notice about any further account movements. A dunning notice is not created for the customer.If the Legal dunning procedure field in the master record contains a date, this means that the account is involved in a legal dunning procedure. The relationship between this date and the dunning date does not affect how the account is processed.The printing of account movements in the legal dunning procedure differs from the normal printing of dunning notices as follows:You must specify a separate form for your dunning procedure in Customizing. For more information, see Customizing (IMG) under Dunning Forms.The dunning program also displays text element 520 "Legal dunning procedure". This makes it possible to display the date of the legal dunning procedure from the master record.The program also displays the documents blocked for dunning and those with a payment method (automatic debit, bank direct debit).Although dunning notices are printed, the dunning level does not change in the master record or in the items. New dunning level = old dunning level.The program only updates the date of the last dunning run.Enter the date manually. + + + + + Identification code for the accounting clerk dealing with dunning letters. + Using this identification code, the accounting clerk whose name is printed on the dunning letters is determined.If this field is not filled, then the entry from the Accounting clerk field is used. + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + The account group is a classifying feature within vendor master records. The account group determines: + the number interval for the account number of the vendor,whether the number is assigned by the user or by the system,which specifications are necessary and/or possible in the master record. + + + + + + + + + + + + + + + Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. + + + + + + Denotes the purchasing organization. + + + + + + Subdivision of a supplier's overall product range according to various criteria. + For each supplier sub-range:The master data is kept on a common basisCertain conditions applyIn the supplier master, you can create different purchasing data and different partner functions for each supplier sub-range.You can also maintain and change the conditions for each supplier sub-range. You assign a material to a supplier sub-range in the info record.In the supplier master, you can maintain different data for particular supplier sub-ranges, such as ordering addresses or terms of payment, for example.When creating a purchase order with a known supplier, different data is only determined if the supplier sub-range is entered in the initial screen.Your supplier Smith in Houston has two sub-ranges: paint and glue.All materials from the "paint" sub-range are ordered in Houston.You have maintained an alternative ordering address in Detroit for the "glue" sub-range.If you order materials from the "glue" sub-range, the supplier sub-range finds the Detroit ordering address. + + + + + Key uniquely identifying a plant. + + + + + + The abbreviated form of the name that identifies the partner function. + + + + + + The sequential number that the system applies when there is more than one partner for a particular partner function. + When you create a sales order for a particular customer, there may be more than one ship-to party defined. The different ship-to parties are numbered sequentially. + + + + + Specifies a partner as the default for a particular partner function. + When you enter more than one partner for a particular partner function (for example, you define three different ship-to parties), you can select one partner as the default. During sales or purchasing processing, if you have defined multiple partners for a partner function, the system prompts you to choose just one partner. The system presents the default partner as the first choice in the pop-up window. + + + + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + + + + + + + Alphanumeric key uniquely identifying the document. + With the supplier number, information from the supplier master record (such as the supplier's address and bank details) is copied into a purchasing document (such as a request for quotation or a purchase order).You can use the supplier number to keep track of requests for quotation, purchase orders and outline agreements. + + + + + Denotes the purchasing organization. + + + + + + Determines which calculation schema (pricing procedure) is to be used in purchasing documents containing this supplier number. + You can use the schema group to specify the calculation schema per purchasing organization or supplier. The relevant calculation schema is determined by reference to the schema group.The effect of this is that the conditions to be maintained in a purchasing document can differ depending on the relevant purchasing organization or supplier.If a calculation schema is only to be valid for certain purchasing organizations or suppliers, proceed as follows:Define the schema group for the purchasing organization or the supplier using the relevant function in the menu "Calculation schema -> Schema groups".Assign the schema group to the calculation schema via "Calculation schema -> Determine schema".Enter the schema group for the supplier in the supplier master records to which the calculation schema is to be assigned. Assign the schema group of the purchasing organization to the relevant purchasing organization using "Calculation schema -> Schema group -> Assign to purch. org.". + + + + + Indicates whether or not the supplier master record is earmarked for deletion. + + + + + + Commonly used trading terms that comply with the standards established by the International Chamber of Commerce (ICC). + Incoterms specify internationally recognized procedures that the shipper and the receiving party must follow for the shipping transaction to be completed successfully.If goods are shipped through a port of departure, the appropriate Incoterm might be: FOB ("Free On Board"). You can provide further details (for example, the name of the port) in the secondary Incoterm field: FOB Boston, for example. + + + + + Additional information for the primary Incoterm. + If the primary Incoterm is, for example, FOB ("Free on Board"), then the second field provides details of the port from which the delivery leaves (for example, "FOB Boston"). + + + + + An incoterms version is an edition containing a list of international terms for transportation that is defined by the International Chamber of Commerce (ICC). + + + + + + Provides additional information for the primary Incoterm. For Incoterms 2010, this field represents: + 1. For sea and inland waterway transport - Port of Shipment2. For any mode of transport - Place of Delivery 2010Incoterms are divided as follows:Group 1: Rules for any mode or modes of transport (including by vessel)Incoterms Incoterms Description Location 1 EXW Ex Works Place of DeliveryFCA Free Carrier Place of DeliveryCPT Carriage Paid To Place of DestinationCIP Carriage & Insurance Paid To Place of DestinationDAF Delivered at Frontier Place of DeliveryDDP Delivered Duty Paid Place of DestinationDDU Delivered Duty Unpaid Place of DestinationGroup 2: Rules for sea and inland waterwaysIncoterms Incoterms Description Location 1 FAS Free Alongside Ship Port of ShipmentFOB Free On Board Port of ShipmentCFR Cost & Freight Port of DestinationCIF Cost Insurance & Freight Port of DestinationDEQ Delivered Eq Quay (Duty Paid) Port of DestinationDES Delivered Ex Ship Port of DestinationIf the primary incoterm is specified as FOB “Free on Board”, the second field provides details of the port from which the delivery leaves, such as FOB Boston. + + + + + Provides additional information for the Incoterms. This field is only available for C-Clauses (if customized appropriately). Note the following for the incoterms versions below: + No Version:This field is disabledIncoterm Version 2000This field is disabled as part of standard delivery unless a customer decides to enable it by the way of Customizing for Sales and Distribution under Master Data -> Business Partners -> Customers -> Billing Document -> Incoterms -> Map Incoterms to Versions.Incoterm Version 2010For this version, the field represents:Sea and inland waterway transport - Port of DestinationAny mode of transport - Place of Destination2010 Incoterms are divided as follows:Group 1: Rules for any mode or modes of transport (including by vessel)Incoterms Incoterms Description Location 2CPT Carriage Paid To Place of DestinationCIP Carriage & Insurance Paid To Place of DestinationGroup 2: Rules for sea and inland waterwaysIncoterms Incoterms Description Location 2CFR Cost & Freight Port of DestinationCIF Cost Insurance & Freight Port of Destination + + + + + Indicator specifying that provision has been made for goods-receipt-based invoice verification for a purchase order item or invoice item. + + + + + + Number of calendar days needed to obtain the material or service if it is procured externally. + If you have different vendors for a material, you must specify an average value. The same applies if you order the material from a fixed vendor that has varying delivery times.If you use the SAP Retail System, the planned delivery time can be suggested from the vendor sub-range in the vendor master record. + + + + + Minimum value specified for purchase orders issued to the relevant supplier. + + + + + + Key for defining payment terms composed of cash discount percentages and payment periods. + It is used in sales orders, purchase orders, and invoices. Terms of payment provide information for:Cash managementDunning proceduresPayment transactionsData can be entered in the field for the terms of payment key in various ways as you enter a business transaction:In most business transactions, the system defaults the key specified in the master record of the customer/vendor in question.In some transactions (for example, credit memos), however, the system does not default the key from the master record. Despite this, you can use the key from the customer/vendor master record by entering "*" in the field.Regardless of whether or not a key is defaulted from the master record, you can manually enter a key during document entry at:item level in sales ordersheader level in purchase orders and invoicesMaster records have separate areas for Financial Accounting, Sales, and Purchasing. You can specify different terms of payment keys in each of these areas. When you then enter a business transaction, the application in question will use the key specified in its area of the master record. + + + + + Determines which date is to be used for price determination (pricing) purposes. + Enter the key for the desired date.If you choose the date of goods receipt, for example, a new price will be determined upon the arrival of the goods, causing the item to be revaluated at this time.NoteIf you have chosen the delivery date as the date for price determination and an item contains several delivery dates (i.e. has a delivery schedule), the first delivery date (the delivery date specified in the first schedule line) is taken. + + + + + Allows you to automatically generate purchase orders from purchase requisitions if the requisition has been assigned to a supplier (source of supply). + If you want to use automatic conversion, note the following additional conditions:In the case of purchase requisitions for materials, you should also select the indicator Autom.purch.ord. in the Purchasing view in the material master record.In the case of purchase requisitions for services, you should also select the indicator Automatic creation of POs for service PReqs in Customizing for Services by choosing:IMG -> MM -> External Services Management -> Source Determination and Default Values- for Client or- for Purchasing Organization + + + + + Key for the currency on which an order placed with a supplier is based. + + + + + + Key for a buyer or a group of buyers, who is/are responsible for certain purchasing activities. + Internally, the purchasing group is responsible for the procurement of a material or a class of materials.Externally, it is the medium through which contacts with the vendor are maintained. + + + + + Indicates whether or not the supplier master record is blocked for the purchasing organization for posting purposes. + + + + + + General shipping strategy for the delivery of goods from the vendor to the customer. + You can define shipping conditions in your system which correspond to the requirements of your company. You can specify a shipping condition in the customer master and in the vendor master.Shipping point determination (outbound delivery):The loading group, the plant and the shipping condition determine the shipping point that will be proposed by the system.Route determination (outbound delivery):Apart from the country and the geographical region of the shipping point, the ship-to party and the transportation group, the shipping condition determines the route that the system proposes in the order for the delivery of the goods. In the delivery, the route proposal also takes the weight group into account.A particular customer always requires immediate delivery. You enter the appropriate shipping condition into the customer master record. This means that when you process orders for this customer, the system automatically proposes the express mail room as a shipping point and the quickest way to the airport as a route.If a shipping condition has been assigned to a sales document type in Customizing, this condition will be proposed by the system in the corresponding sales document. If there is no assignment, the system copies the relevant data from the corresponding customer master record of the sold-to party. You cannot change this value during delivery processing. The shipping condition will not be copied from the delivery into the shipment. The shipping condition is one of several criteria for selecting deliveries when you create a shipment. You can enter a shipping condition manually in the shipment where it only serves as a characteristic for grouping shipments. + + + + + Means of classifying suppliers according to their significance to your company. + The indicator serves to assign the supplier to one of the categories A, B or C, in accordance with ABC analysis.'A' category suppliers, for instance, are those accounting for the greatest share of the company's total annual spend (in value terms). + + + + + This telephone number is maintained in the supplier master record and adopted in the purchasing document. + + + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + The account group is a classifying feature within vendor master records. The account group determines: + the number interval for the account number of the vendor,whether the number is assigned by the user or by the system,which specifications are necessary and/or possible in the master record. + + + + + + + + + + + + + Specifies an alphanumeric key that uniquely identifies the supplier in the SAP system. + + + + + + The company code is an organizational unit within financial accounting. + + + + + + This indicator is used to classify the different types of withholding tax. + Withholding tax types classify particular features of a withholding tax including:The time at which the withholding tax is postedThe basis on which the base amount is calculatedThe basis for accumulation (if applicable)Withholding tax types are to be distinguished from withholding tax codes, to which are allocated the withholding tax percentage rate example.Whether a withholding tax can be defined as an existing type by means of a new code, or if a new type needs to be defined will depend on the type of transaction (see below).Note that a business transaction can only be assigned one withholding tax code per withholding tax type. If the business transaction is subject to several withholding taxes simultaneously, these must be represented by different types.This is the case in Argentina for example, where up to four kinds of withholding tax per business transaction are possible. + + + + + Date from which withholding tax exemption applies. + + + + + + Date on which withholding tax exemption expires. + + + + + + Indicator used to classify different types of exemption from liability to a particular withholding tax. + These indicators can be defined per withholding tax type in the vendor master record. + + + + + + The type of recipient can be defined in the vendor master record. + It is used to group vendors together according to particular characteristics such as occupations that may be subject to the same withholding tax type, but which are required to pay different percentage rates (as defined by the withholding tax code).Application in ThailandThis corresponds to the official Thai form number (Phaw.Ngor.Daw) and is used to determine the sequential numbering of a withholding tax certificate. The form number is defined in the vendor master record. + + + + + Numbered assigned by the relevant authorities for exemption from withholding tax. + This number must be entered in the system as follows:In the vendor master record in the case of vendorsFor customers, in Customizing under the settings for withholding tax information for the company code per withholding tax type. + + + + + One or more "withholding tax codes" are assigned to each withholding tax type. One of the things these codes determine is the various percentage rates for the withholding tax type. + Note that when processing a business transaction, no more than one withholding tax code can be assigned per withholding tax type. If the business transaction is subject to more than one withholding taxes, these must be represented in the system by defining various withholding tax types. + + + + + Rate of exemption from withholding tax. + Those persons/activities subject to withholding tax can be exempted from withholding tax up to the percentage rate you enter here. This exemption rate refers to the withholding tax amount itself and not to the whole amount liable to withholding tax (withholding tax base amount).The gross amount of an invoice is 100.00 and the withholding tax base amount is defined as gross. The withholding tax rate is 10% meaning that the withholding tax amount is 10.00. Given an exemption rate of 30%, the withholding tax amount is reduced to 7.00. + + + + + This is a number issued by the tax authorities per withholding tax type. + This number must be specified in Customizing either:(a) As part of the withholding tax information defined for the company code, or(b) As part of the withholding tax information defined in the customer or vendor master record. + + + + + The authorization group allows extended authorization protection for particular objects. The authorization groups are freely definable. The authorization groups usually occur in authorization objects together with an activity. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + aggregate + groupby + filter + + + + + + + + + + + diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/notes-mashup.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/notes-mashup.cds new file mode 100644 index 000000000..6dbea08b1 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/notes-mashup.cds @@ -0,0 +1,32 @@ +using { API_BUSINESS_PARTNER } from './external/API_BUSINESS_PARTNER'; + +/** + * Simplified view on external addresses, which is used as an association target in Notes. + */ +entity my.bookshop.NoteableAddresses as select from API_BUSINESS_PARTNER.A_BusinessPartnerAddress mixin { + // bi-directional association + notes : Composition of many bookshop.Notes on notes.address.businessPartner = $projection.businessPartner and notes.address.ID = $projection.ID +} into { + key AddressID as ID, + key BusinessPartner as businessPartner, + @readonly Country as country, + @readonly CityName as city, + @readonly PostalCode as postalCode, + @readonly StreetName as street, + @readonly HouseNumber as houseNumber, + notes +}; + +/* + * Extend Notes with references to external Addresses. + */ +using { my.bookshop } from '../db/index'; +extend bookshop.Notes { + address: Association to bookshop.NoteableAddresses; +} + +using { NotesService } from './notes-service'; +extend service NotesService with { + @readonly + entity Addresses as projection on bookshop.NoteableAddresses +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/notes-service.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/notes-service.cds new file mode 100644 index 000000000..1a4fb617c --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/notes-service.cds @@ -0,0 +1,6 @@ +using my.bookshop from '../db/notes'; + +@path: 'notes' +service NotesService { + entity Notes as projection on bookshop.Notes; +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/pom.xml b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/pom.xml new file mode 100644 index 000000000..8ff375092 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/pom.xml @@ -0,0 +1,284 @@ + + 4.0.0 + + + bookshop-parent + my + ${revision} + + + bookshop + jar + + bookshop + + + + + + com.sap.cds + cds-starter-spring-boot + + + + com.sap.cds + cds-adapter-odata-v4 + runtime + + + org.apache.commons + commons-collections4 + 4.4 + + + com.sap.cds + cds-feature-mt + 4.3.0 + + + com.sap.cds + sdm + 1.0.0-RC1 + + + com.sap.cds + cds-starter-cloudfoundry + runtime + + + com.sap.cds + cds-feature-xsuaa + + + com.sap.cloud.security.xsuaa + xsuaa-spring-boot-starter + + + + + + com.sap.cds + cds-starter-k8s + runtime + + + com.sap.cds + cds-feature-xsuaa + + + com.sap.cloud.security.xsuaa + xsuaa-spring-boot-starter + + + + + + com.sap.cds + cds-feature-enterprise-messaging + runtime + + + + com.sap.cds + cds-feature-remote-odata + runtime + + + + com.sap.cds + cds-feature-change-tracking + runtime + + + + + com.sap.cloud.sdk.cloudplatform + resilience + + + + com.sap.cloud.sdk + sdk-core + + + + com.sap.cloud.sdk.cloudplatform + connectivity-apache-httpclient4 + + + + + com.h2database + h2 + runtime + + + + org.xerial + sqlite-jdbc + runtime + + + + com.sap.hcp.cf.logging + cf-java-logging-support-servlet-jakarta + ${cf-java-logging-support.version} + + + + com.sap.hcp.cf.logging + cf-java-logging-support-logback + ${cf-java-logging-support.version} + + + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.security + spring-security-test + test + + + + org.springframework.boot + spring-boot-starter-webflux + test + + + + + org.springframework.boot + spring-boot-devtools + true + + + + + bookshop + + + + org.springframework.boot + spring-boot-maven-plugin + + false + + + + repackage + + repackage + + + exec + + + + + + + org.graalvm.buildtools + native-maven-plugin + + + + + com.sap.cds + cds-maven-plugin + ${cds.services.version} + + + cds.clean + + clean + + + + + cds.install-node + + install-node + + + ${cdsdk-global} + + + + + cds.install-dependencies + + npm + + + install @sap/cds-dk@${cds.install-cdsdk.version} @sap/cds-mtxs@^3 --no-save + + + + + cds.resolve + + resolve + + + + + cds.build + + cds + + + + build --for java --opts contentLocalizedEdmx=false + deploy --to h2 --with-mocks --dry > + "${project.basedir}/src/main/resources/schema.sql" + deploy --to h2 --dry > + "${project.basedir}/src/main/resources/schema-nomocks.sql" + compile srv/cat-service.cds -2 openapi --openapi:url /api/browse > + "${project.basedir}/src/main/resources/swagger/openapi.json" + + + + + + cds.generate + + generate + + + cds.gen + true + true + true + + + + + + + + + + + cdsdk-global + + true + + + + diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/review-service.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/review-service.cds new file mode 100644 index 000000000..60debda19 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/review-service.cds @@ -0,0 +1,30 @@ +using {my.bookshop as my} from '../db/index'; + +@path : 'review' +service ReviewService { + entity Reviews as projection on my.Reviews; + + @readonly + entity Books as projection on my.Books excluding { + createdBy, + modifiedBy + } + + @readonly + entity Authors as projection on my.Authors; + + // access control restrictions + annotate Reviews with @restrict : [ + { + grant : '*', + to : 'authenticated-user', + where : 'createdBy=$user' + }, + { + grant : '*', + to : 'admin', + } + ]; +} + +annotate ReviewService.Reviews with @odata.draft.enabled; diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/Application.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/Application.java new file mode 100644 index 000000000..d4ab598c7 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/Application.java @@ -0,0 +1,29 @@ +package my.bookshop; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; + +import com.sap.hcp.cf.logging.servlet.filter.RequestLoggingFilter; + +import jakarta.servlet.DispatcherType; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + @Bean + public FilterRegistrationBean loggingFilter() { + FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>(); + filterRegistrationBean.setFilter(new RequestLoggingFilter()); + filterRegistrationBean.setName("request-logging"); + filterRegistrationBean.addUrlPatterns("/*"); + filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST); + return filterRegistrationBean; + } + +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/MessageKeys.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/MessageKeys.java new file mode 100644 index 000000000..9f217eb93 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/MessageKeys.java @@ -0,0 +1,19 @@ +package my.bookshop; + +public class MessageKeys { + + public static final String QUANTITY_REQUIRE_MINIMUM = "quantity.require.minimum"; + public static final String BOOK_REQUIRE_STOCK = "book.require.stock"; + public static final String BOOK_ADDED_ORDER = "book.added.order"; + public static final String BOOK_MISSING = "book.missing"; + public static final String ORDERITEM_MISSING = "orderitem.missing"; + public static final String ORDER_MISSING = "order.missing"; + public static final String ORDER_INDRAFT = "order.indraft"; + public static final String BUPA_MISSING = "bupa.missing"; + + public static final String REVIEW_ADDED = "review.added"; + public static final String REVIEW_ADD_FORBIDDEN = "review.add.forbidden"; + public static final String ORDER_EXCEEDS_STOCK = "order.exceeds.stock"; + public static final String BOOK_IMPORT_FAILED = "book.import.failed"; + public static final String BOOK_IMPORT_INVALID_CSV = "book.import.invalid.csv"; +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/RatingCalculator.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/RatingCalculator.java new file mode 100644 index 000000000..0539c9059 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/RatingCalculator.java @@ -0,0 +1,64 @@ +package my.bookshop; + +import static cds.gen.my.bookshop.Bookshop_.BOOKS; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.OptionalDouble; +import java.util.stream.Stream; + +import org.springframework.stereotype.Component; + +import com.sap.cds.Result; +import com.sap.cds.ql.Select; +import com.sap.cds.ql.Update; +import com.sap.cds.services.persistence.PersistenceService; + +import cds.gen.my.bookshop.Books; +import cds.gen.my.bookshop.Reviews; + +/** + * Takes care of calculating the average rating of a book based on its review + * ratings. + */ +@Component +public class RatingCalculator { + + private PersistenceService db; + + RatingCalculator(PersistenceService db) { + this.db = db; + } + + /** + * Initializes the ratings for all existing books based on their reviews. + */ + public void initBookRatings() { + Result result = db.run(Select.from(BOOKS).columns(b -> b.ID())); + for (Books book : result.listOf(Books.class)) { + setBookRating(book.getId()); + } + } + + /** + * Sets the average rating for the given book. + * + * @param bookId + */ + public void setBookRating(String bookId) { + Result run = db.run(Select.from(BOOKS, b -> b.filter(b.ID().eq(bookId)).reviews())); + + Stream ratings = run.streamOf(Reviews.class).map(r -> r.getRating().doubleValue()); + BigDecimal rating = getAvgRating(ratings); + + db.run(Update.entity(BOOKS).byId(bookId).data(Books.RATING, rating)); + } + + static BigDecimal getAvgRating(Stream ratings) { + OptionalDouble avg = ratings.mapToDouble(Double::doubleValue).average(); + if (!avg.isPresent()) { + return BigDecimal.ZERO; + } + return BigDecimal.valueOf(avg.getAsDouble()).setScale(1, RoundingMode.HALF_UP); + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/CustomFeatureToggleProvider.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/CustomFeatureToggleProvider.java new file mode 100644 index 000000000..d4dfec9e7 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/CustomFeatureToggleProvider.java @@ -0,0 +1,30 @@ +package my.bookshop.config; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import com.sap.cds.services.request.FeatureTogglesInfo; +import com.sap.cds.services.request.ParameterInfo; +import com.sap.cds.services.request.UserInfo; +import com.sap.cds.services.runtime.FeatureTogglesInfoProvider; + +@Component +@Profile("cloud") // locally, feature toggles are configured directly with mock users +public class CustomFeatureToggleProvider implements FeatureTogglesInfoProvider { + + @Override + public FeatureTogglesInfo get(UserInfo userInfo, ParameterInfo parameterInfo) { + if (userInfo.getTenant() == null && userInfo.isSystemUser()) { + // technical provider user runs with all feature toggles + return FeatureTogglesInfo.all(); + } + + Map toggles = new HashMap<>(); + toggles.put("isbn", userInfo.hasRole("expert")); + toggles.put("discount", userInfo.hasRole("premium-customer")); + return FeatureTogglesInfo.create(toggles); + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/DestinationConfiguration.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/DestinationConfiguration.java new file mode 100644 index 000000000..94f796a4a --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/DestinationConfiguration.java @@ -0,0 +1,37 @@ +package my.bookshop.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.annotation.Profile; +import org.springframework.context.event.EventListener; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import com.sap.cloud.sdk.cloudplatform.connectivity.DefaultDestinationLoader; +import com.sap.cloud.sdk.cloudplatform.connectivity.DefaultHttpDestination; +import com.sap.cloud.sdk.cloudplatform.connectivity.DestinationAccessor; +import com.sap.cloud.sdk.cloudplatform.security.BasicCredentials; + +@Component +@Profile("mocked") +public class DestinationConfiguration { + + @Autowired + private Environment environment; + + @EventListener + void applicationReady(ApplicationReadyEvent ready) { + Integer port = environment.getProperty("local.server.port", Integer.class); + String destinationName = environment.getProperty("cds.remote.services.'[API_BUSINESS_PARTNER]'.destination.name"); + if(port != null && destinationName != null) { + DefaultHttpDestination httpDestination = DefaultHttpDestination + .builder("http://localhost:" + port) + .basicCredentials(new BasicCredentials("authenticated", "")) + .name(destinationName).build(); + + DestinationAccessor.prependDestinationLoader( + new DefaultDestinationLoader().registerDestination(httpDestination)); + } + } + +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/SwaggerResourceConfig.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/SwaggerResourceConfig.java new file mode 100644 index 000000000..af8b24b25 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/SwaggerResourceConfig.java @@ -0,0 +1,14 @@ +package my.bookshop.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class SwaggerResourceConfig implements WebMvcConfigurer { + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/swagger/**").addResourceLocations("classpath:/swagger/"); + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/WebSecurityConfig.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/WebSecurityConfig.java new file mode 100644 index 000000000..346a784fe --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/config/WebSecurityConfig.java @@ -0,0 +1,25 @@ +package my.bookshop.config; + +import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; + +@Configuration +@ConditionalOnWebApplication +@EnableWebSecurity +@Order(1) +public class WebSecurityConfig { + + @Bean + public SecurityFilterChain configure(HttpSecurity http) throws Exception { + return http.securityMatchers(s -> s.requestMatchers(antMatcher("/actuator/health"), antMatcher("/swagger/**"))) // + .csrf(c -> c.disable()).authorizeHttpRequests(a -> a.anyRequest().permitAll()) + .build(); + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceAddressHandler.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceAddressHandler.java new file mode 100644 index 000000000..6d113f231 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceAddressHandler.java @@ -0,0 +1,154 @@ +package my.bookshop.handlers; + +import static cds.gen.adminservice.AdminService_.ADDRESSES; + +import java.time.Duration; +import java.util.Optional; +import java.util.stream.Stream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import com.sap.cds.Result; +import com.sap.cds.ql.CQL; +import com.sap.cds.ql.Insert; +import com.sap.cds.ql.Predicate; +import com.sap.cds.ql.Select; +import com.sap.cds.ql.Upsert; +import com.sap.cds.ql.cqn.CqnSelect; +import com.sap.cds.ql.cqn.Modifier; +import com.sap.cds.services.ErrorStatuses; +import com.sap.cds.services.EventContext; +import com.sap.cds.services.ServiceException; +import com.sap.cds.services.cds.CdsReadEventContext; +import com.sap.cds.services.cds.CqnService; +import com.sap.cds.services.draft.DraftService; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.Before; +import com.sap.cds.services.handler.annotations.On; +import com.sap.cds.services.handler.annotations.ServiceName; +import com.sap.cds.services.persistence.PersistenceService; +import com.sap.cloud.sdk.cloudplatform.resilience.ResilienceConfiguration; +import com.sap.cloud.sdk.cloudplatform.resilience.ResilienceConfiguration.TimeLimiterConfiguration; +import com.sap.cloud.sdk.cloudplatform.resilience.ResilienceDecorator; + +import cds.gen.adminservice.Addresses; +import cds.gen.adminservice.Addresses_; +import cds.gen.adminservice.AdminService_; +import cds.gen.adminservice.Orders; +import cds.gen.api_business_partner.ApiBusinessPartner; +import cds.gen.api_business_partner.ApiBusinessPartner_; +import cds.gen.api_business_partner.BusinessPartnerChangedContext; +import my.bookshop.MessageKeys; + +/** + * Custom handler for the Admin Service Addresses, which come from a remote S/4 System + */ +@Component +@ServiceName(AdminService_.CDS_NAME) +public class AdminServiceAddressHandler implements EventHandler { + + private final static Logger logger = LoggerFactory.getLogger(AdminServiceAddressHandler.class); + + // We are mashing up the AdminService with two other services... + private final PersistenceService db; + private final ApiBusinessPartner bupa; + + AdminServiceAddressHandler(PersistenceService db, @Qualifier(ApiBusinessPartner_.CDS_NAME) ApiBusinessPartner bupa) { + this.db = db; + this.bupa = bupa; + } + + // Delegate ValueHelp requests to S/4 backend, fetching current user's addresses from there + @On(entity = Addresses_.CDS_NAME) + public void readAddresses(CdsReadEventContext context) { + if(context.getCqn().ref().segments().size() != 1) { + return; // no value help request + } + + // add BusinessPartner where condition + String businessPartner = context.getUserInfo().getAttributeValues("businessPartner").stream().findFirst() + .orElseThrow(() -> new ServiceException(ErrorStatuses.FORBIDDEN, MessageKeys.BUPA_MISSING)); + + CqnSelect select = CQL.copy(context.getCqn(), new Modifier() { + + public Predicate where(Predicate original) { + Predicate where = CQL.get(Addresses.BUSINESS_PARTNER).eq(businessPartner); + if(original != null) { + where = original.and(where); + } + return where; + } + + }); + + // using Cloud SDK resilience capabilities.. + ResilienceConfiguration config = ResilienceConfiguration.of(AdminServiceAddressHandler.class) + .timeLimiterConfiguration(TimeLimiterConfiguration.of(Duration.ofSeconds(10))); + + context.setResult(ResilienceDecorator.executeSupplier(() -> { + // ..to access the S/4 system in a resilient way.. + logger.info("Delegating GET Addresses to S/4 service"); + return bupa.run(select); + }, config, (t) -> { + // ..falling back to the already replicated addresses in our own database + logger.warn("Falling back to already replicated Addresses"); + return db.run(select); + })); + } + + // Replicate chosen addresses from S/4 when filling orders + @Before(event = { CqnService.EVENT_CREATE, CqnService.EVENT_UPDATE, DraftService.EVENT_DRAFT_PATCH }) + public void patchAddressId(EventContext context, Stream orders) { + String businessPartner = context.getUserInfo().getAttributeValues("businessPartner").stream().findFirst() + .orElseThrow(() -> new ServiceException(ErrorStatuses.FORBIDDEN, MessageKeys.BUPA_MISSING)); + + orders.filter(o -> o.getShippingAddressId() != null).forEach(order -> { + String addressId = order.getShippingAddressId(); + Result replica = db.run(Select.from(ADDRESSES).where(a -> a.businessPartner().eq(businessPartner).and(a.ID().eq(addressId)))); + // check if the address was not yet replicated + if(replica.rowCount() < 1) { + logger.info("Replicating Address '{}' from S/4 service", addressId); + Addresses remoteAddress = bupa.run(Select.from(ADDRESSES) + .where(a -> a.businessPartner().eq(businessPartner).and(a.ID().eq(addressId)))) + .single(Addresses.class); + + remoteAddress.setTombstone(false); + db.run(Insert.into(ADDRESSES).entry(remoteAddress)); + } + order.setShippingAddressBusinessPartner(businessPartner); + }); + } + + @On(service = ApiBusinessPartner_.CDS_NAME) + public void updateBusinessPartnerAddresses(BusinessPartnerChangedContext context) { + logger.info(">> received: " + context.getData()); + String businessPartner = context.getData().getBusinessPartner(); + + // fetch affected entries from local replicas + Result replicas = db.run(Select.from(ADDRESSES).where(a -> a.businessPartner().eq(businessPartner))); + if(replicas.rowCount() > 0) { + logger.info("Updating Addresses for BusinessPartner '{}'", businessPartner); + // fetch changed data from S/4 -> might be less than local due to deletes + Result remoteAddresses = bupa.run(Select.from(ADDRESSES).where(a -> a.businessPartner().eq(businessPartner))); + // update replicas or add tombstone if external address was deleted + replicas.streamOf(Addresses.class).forEach(rep -> { + Optional matching = remoteAddresses + .streamOf(Addresses.class) + .filter(ext -> ext.getId().equals(rep.getId())) + .findFirst(); + + if(!matching.isPresent()) { + rep.setTombstone(true); + } else { + matching.get().forEach(rep::put); + } + }); + // update local replicas with changes from S/4 + db.run(Upsert.into(ADDRESSES).entries(replicas)); + } + } + +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceAuditHandler.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceAuditHandler.java new file mode 100644 index 000000000..b8837772a --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceAuditHandler.java @@ -0,0 +1,144 @@ +package my.bookshop.handlers; + +import static cds.gen.adminservice.AdminService_.ORDERS; + +import java.util.Arrays; +import java.util.Optional; +import java.util.stream.Stream; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import com.sap.cds.ql.Select; +import com.sap.cds.ql.cqn.CqnDelete; +import com.sap.cds.services.EventContext; +import com.sap.cds.services.auditlog.Action; +import com.sap.cds.services.auditlog.AuditLogService; +import com.sap.cds.services.auditlog.ChangedAttribute; +import com.sap.cds.services.auditlog.ConfigChange; +import com.sap.cds.services.auditlog.DataObject; +import com.sap.cds.services.auditlog.KeyValuePair; +import com.sap.cds.services.cds.CdsDeleteEventContext; +import com.sap.cds.services.cds.CqnService; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.Before; +import com.sap.cds.services.handler.annotations.ServiceName; +import com.sap.cds.services.persistence.PersistenceService; + +import cds.gen.adminservice.AdminService_; +import cds.gen.adminservice.Orders; +import cds.gen.adminservice.Orders_; + +/** + * A custom handler that creates AuditLog messages. + */ +@Component +@ServiceName(AdminService_.CDS_NAME) +class AdminServiceAuditHandler implements EventHandler { + + private final PersistenceService db; + + private final AuditLogService auditLog; + + AdminServiceAuditHandler(PersistenceService db, AuditLogService auditLog) { + this.db = db; + this.auditLog = auditLog; + } + + @Before(event = { CqnService.EVENT_CREATE }) + public void beforeCreateOrder(Stream orders) { + orders.forEach(order -> { + ConfigChange cfgChange = createConfigChange(order, null); + this.auditLog.logConfigChange(Action.CREATE, cfgChange); + }); + } + + @Before(event = { CqnService.EVENT_UPDATE, CqnService.EVENT_UPSERT }) + public void beforeUpdateOrUpsertOrder(EventContext context, Stream orders) { + orders.forEach(order -> { + ConfigChange cfgChange = null; + Action action = null; + Optional oldOrders = readOldOrders(order.getId()); + if (oldOrders.isPresent()) { + if (!StringUtils.equals(order.getCurrencyCode(), oldOrders.get().getCurrencyCode())) { + cfgChange = createConfigChange(order, oldOrders.get()); + action = Action.UPDATE; + } + } else { + cfgChange = createConfigChange(order, null); + action = Action.CREATE; + } + if (cfgChange != null && action != null) { + auditCfgChange(action, cfgChange, context); + } + }); + } + + @Before(event = { CqnService.EVENT_DELETE }, entity = { Orders_.CDS_NAME }) + public void beforeDelete(CdsDeleteEventContext context) { + // prepare a select statement to read old currency code + Select ordersSelect = toSelect(context.getCqn()); + + // read old order number from DB + this.db.run(ordersSelect).first(Orders.class).ifPresent(oldOrders -> { + ConfigChange cfgChange = createConfigChange(null, oldOrders); + auditCfgChange(Action.DELETE, cfgChange, context); + }); + } + + private void auditCfgChange(final Action action, final ConfigChange cfgChange, EventContext context) { + // create new request context and send audit log message into provider tenant + context.getCdsRuntime().requestContext().systemUserProvider().run(ctx -> { + this.auditLog.logConfigChange(action, cfgChange); + }); + } + + private Optional readOldOrders(String ordersId) { + // prepare a select statement to read old order number + Select ordersSelect = Select.from(ORDERS).columns(Orders_::OrderNo) + .where(o -> o.ID().eq(ordersId).and(o.IsActiveEntity().eq(true))); + + // read old orders from DB + return this.db.run(ordersSelect).first(Orders.class); + } + + private static ConfigChange createConfigChange(Orders orders, Orders oldOrders) { + ChangedAttribute currencyCodeAttr = createChangedAttribute(orders != null ? orders.getCurrencyCode() : null, + oldOrders != null ? oldOrders.getCurrencyCode() : null); + + ConfigChange cfgChange = ConfigChange.create(); + cfgChange.setDataObject(createDataObject(orders != null ? orders : oldOrders)); + cfgChange.setAttributes(Arrays.asList(currencyCodeAttr)); + return cfgChange; + } + + private static DataObject createDataObject(Orders order) { + KeyValuePair id = createId(order); + + DataObject dataObject = DataObject.create(); + dataObject.setType(Orders_.CDS_NAME); + dataObject.setId(Arrays.asList(id)); + return dataObject; + } + + private static ChangedAttribute createChangedAttribute(String newValue, String oldValue) { + ChangedAttribute attribute = ChangedAttribute.create(); + attribute.setName(Orders.CURRENCY_CODE); + attribute.setOldValue(oldValue); + attribute.setNewValue(newValue); + return attribute; + } + + private static KeyValuePair createId(Orders order) { + KeyValuePair id = KeyValuePair.create(); + id.setKeyName(Orders.ID); + id.setValue(order.getId()); + return id; + } + + private static Select toSelect(CqnDelete delete) { + Select select = Select.from(delete.ref()); + delete.where().ifPresent(select::where); + return select; + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceHandler.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceHandler.java new file mode 100644 index 000000000..814ddcfa4 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/AdminServiceHandler.java @@ -0,0 +1,456 @@ +package my.bookshop.handlers; + +import static cds.gen.adminservice.AdminService_.ORDERS; +import static cds.gen.adminservice.AdminService_.ORDER_ITEMS; +import static cds.gen.my.bookshop.Bookshop_.BOOKS; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import org.springframework.stereotype.Component; + +import com.sap.cds.Result; +import com.sap.cds.ql.Select; +import com.sap.cds.ql.Update; +import com.sap.cds.ql.Upsert; +import com.sap.cds.ql.cqn.CqnAnalyzer; +import com.sap.cds.reflect.CdsModel; +import com.sap.cds.services.ErrorStatuses; +import com.sap.cds.services.EventContext; +import com.sap.cds.services.ServiceException; +import com.sap.cds.services.cds.CdsUpdateEventContext; +import com.sap.cds.services.cds.CqnService; +import com.sap.cds.services.draft.DraftCancelEventContext; +import com.sap.cds.services.draft.DraftPatchEventContext; +import com.sap.cds.services.draft.DraftService; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.Before; +import com.sap.cds.services.handler.annotations.On; +import com.sap.cds.services.handler.annotations.ServiceName; +import com.sap.cds.services.messages.Messages; +import com.sap.cds.services.persistence.PersistenceService; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import cds.gen.adminservice.BooksAddToOrderContext; +import cds.gen.adminservice.AdminService; +import cds.gen.adminservice.AdminService_; +import cds.gen.adminservice.Books; +import cds.gen.adminservice.Books_; +import cds.gen.adminservice.OrderItems; +import cds.gen.adminservice.OrderItems_; +import cds.gen.adminservice.Orders; +import cds.gen.adminservice.Upload; +import cds.gen.adminservice.Upload_; +import cds.gen.my.bookshop.Bookshop_; +import my.bookshop.MessageKeys; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.Map; + +import com.sap.cds.ql.Insert; +import com.sap.cds.ql.cqn.CqnComparisonPredicate; +import com.sap.cds.ql.cqn.CqnConnectivePredicate; +import com.sap.cds.ql.cqn.CqnElementRef; +import com.sap.cds.ql.cqn.CqnLiteral; +import com.sap.cds.ql.cqn.CqnPredicate; +import com.sap.cds.ql.cqn.CqnReference; +import com.sap.cds.ql.cqn.CqnSelect; +import com.sap.cds.ql.cqn.CqnStructuredTypeRef; + +/** + * Custom business logic for the "Admin Service" (see admin-service.cds) + * + * Handles creating and editing orders. + */ +@Component +@ServiceName(AdminService_.CDS_NAME) +class AdminServiceHandler implements EventHandler { + + private static final Logger logger = LoggerFactory.getLogger(AdminServiceHandler.class); + + private final AdminService.Draft adminService; + + private final PersistenceService db; + + private final Messages messages; + + private final CqnAnalyzer analyzer; + + AdminServiceHandler(AdminService.Draft adminService, PersistenceService db, Messages messages, CdsModel model) { + this.adminService = adminService; + this.db = db; + this.messages = messages; + + // model is a tenant-dependant model proxy + this.analyzer = CqnAnalyzer.create(model); + } + + /** + * Validate correctness of an order before finishing the order proces: + * 1. Check Order quantity for each Item and return a message if quantity is empty or <= 0 + * 2. Check Order quantity for each Item is available, return message if the stock is too low + * + * @param orders + */ + @Before(event = { CqnService.EVENT_CREATE, CqnService.EVENT_UPSERT, CqnService.EVENT_UPDATE }) + public void beforeCreateOrder(Stream orders, EventContext context) { + orders.forEach(order -> { + // reset total + order.setTotal(BigDecimal.valueOf(0)); + if(order.getItems() != null) { + order.getItems().forEach(orderItem -> { + // validation of the Order creation request + Integer quantity = orderItem.getQuantity(); + if (quantity == null || quantity <= 0) { + // errors with localized messages from property files + // exceptions abort the request and set an error http status code + // messages in contrast allow to collect multiple errors + messages.error(MessageKeys.QUANTITY_REQUIRE_MINIMUM) + .target("in", ORDERS, o -> o.Items(i -> i.ID().eq(orderItem.getId()).and(i.IsActiveEntity().eq(orderItem.getIsActiveEntity()))).quantity()); + } + + String bookId = orderItem.getBookId(); + + if(quantity == null || quantity <= 0 || bookId == null) { + return; // follow up validations rely on these + } + + // calculate the actual quantity difference + // FIXME this should handle book changes, currently only quantity changes are handled + int diffQuantity = quantity - db.run(Select.from(Bookshop_.ORDER_ITEMS).columns(i -> i.quantity()).byId(orderItem.getId())) + .first(OrderItems.class).map(i -> i.getQuantity()).orElse(0); + + // check if enough books are available + Result result = db.run(Select.from(BOOKS).columns(b -> b.ID(), b -> b.stock(), b -> b.price()).byId(bookId)); + result.first(Books.class).ifPresent(book -> { + if (book.getStock() < diffQuantity) { + // Tip: you can have localized messages and use parameters in your messages + messages.error(MessageKeys.BOOK_REQUIRE_STOCK, book.getStock()) + .target("in", ORDERS, o -> o.Items(i -> i.ID().eq(orderItem.getId()).and(i.IsActiveEntity().eq(orderItem.getIsActiveEntity()))).quantity()); + return; // no need to update follow-up values with invalid quantity / stock + } + + // update the book with the new stock + book.setStock(book.getStock() - diffQuantity); + db.run(Update.entity(BOOKS).data(book)); + + // update the amount + BigDecimal updatedAmount = book.getPrice().multiply(BigDecimal.valueOf(quantity)); + orderItem.setAmount(updatedAmount); + + // update the total + order.setTotal(order.getTotal().add(updatedAmount)); + }); + }); + } + }); + } + + /** + * Calculate the total order value preview when editing an order item + * + * @param context + * @param orderItem + */ + @Before(event = DraftService.EVENT_DRAFT_PATCH) + public void patchOrderItems(DraftPatchEventContext context, OrderItems orderItem) { + // check if quantity or book was updated + Integer quantity = orderItem.getQuantity(); + String bookId = orderItem.getBookId(); + String orderItemId = orderItem.getId(); + BigDecimal amount = calculateAmountInDraft(orderItemId, quantity, bookId, true); + if (amount != null) { + orderItem.setAmount(amount); + } + } + + /** + * Calculate the total order value preview when deleting an order item from the order + * + * @param context + */ + @Before(event = DraftService.EVENT_DRAFT_CANCEL, entity = OrderItems_.CDS_NAME) + public void cancelOrderItems(DraftCancelEventContext context) { + String orderItemId = (String) analyzer.analyze(context.getCqn()).targetKeys().get(OrderItems.ID); + if(orderItemId != null) { + calculateAmountInDraft(orderItemId, 0, null, false); + } + } + + private BigDecimal calculateAmountInDraft(String orderItemId, Integer newQuantity, String newBookId, boolean includeWarnings) { + Integer quantity = newQuantity; + String bookId = newBookId; + if (quantity == null && bookId == null) { + return null; // nothing changed + } + + // get the order item that was updated (to get access to the book price, quantity and order total) + Result result = adminService.run(Select.from(ORDER_ITEMS) + .columns(o -> o.quantity(), o -> o.amount(), + o -> o.book().expand(b -> b.ID(), b -> b.price()), + o -> o.parent().expand(p -> p.ID(), p -> p.total())) + .where(o -> o.ID().eq(orderItemId).and(o.IsActiveEntity().eq(false)))); + OrderItems itemToPatch = result.first(OrderItems.class).orElseThrow(notFound(MessageKeys.ORDERITEM_MISSING)); + BigDecimal bookPrice = null; + + // fallback to existing values + if(quantity == null) { + quantity = itemToPatch.getQuantity(); + } + + if(bookId == null && itemToPatch.getBook() != null) { + bookId = itemToPatch.getBook().getId(); + bookPrice = itemToPatch.getBook().getPrice(); + } + + if(quantity == null || bookId == null) { + return null; // not enough data available + } + + // only warn about invalid values as we are in draft mode + if(includeWarnings && quantity <= 0) { + // Tip: add additional messages with localized messages from property files + // these messages are transported in sap-messages and do not abort the request + messages.warn(MessageKeys.QUANTITY_REQUIRE_MINIMUM); + } + + // get the price of the updated book ID + if(bookPrice == null) { + result = db.run(Select.from(BOOKS).byId(bookId).columns(b -> b.price())); + Books book = result.first(Books.class).orElseThrow(notFound(MessageKeys.BOOK_MISSING)); + bookPrice = book.getPrice(); + } + + // update the amount of the order item + BigDecimal updatedAmount = bookPrice.multiply(BigDecimal.valueOf(quantity)); + + // update the order's total + BigDecimal previousAmount = defaultZero(itemToPatch.getAmount()); + BigDecimal currentTotal = defaultZero(itemToPatch.getParent().getTotal()); + BigDecimal newTotal = currentTotal.subtract(previousAmount).add(updatedAmount); + adminService.patchDraft(Update.entity(ORDERS) + .where(o -> o.ID().eq(itemToPatch.getParent().getId()).and(o.IsActiveEntity().eq(false))) + .data(Orders.TOTAL, newTotal)); + + return updatedAmount; + } + + /** + * Adds a book to an order + * @param context + */ + @On(entity = Books_.CDS_NAME) + public void addBookToOrder(BooksAddToOrderContext context) { + String orderId = context.getOrderId(); + List orders = adminService.run(Select.from(ORDERS).columns(o -> o._all(), o -> o.Items().expand()).where(o -> o.ID().eq(orderId))).listOf(Orders.class); + Orders order = orders.stream().filter(p -> p.getIsActiveEntity()).findFirst().orElse(null); + + // check that the order with given ID exists and is not in draft-mode + if((orders.size() > 0 && order == null) || orders.size() > 1) { + throw new ServiceException(ErrorStatuses.CONFLICT, MessageKeys.ORDER_INDRAFT); + } else if (orders.size() <= 0) { + throw new ServiceException(ErrorStatuses.NOT_FOUND, MessageKeys.ORDER_MISSING); + } + + if(order.getItems() == null) { + order.setItems(new ArrayList<>()); + } + + // get ID of the book on which the action was called (bound action) + String bookId = (String) analyzer.analyze(context.getCqn()).targetKeys().get(Books.ID); + + // create order item + OrderItems newItem = OrderItems.create(); + newItem.setId(UUID.randomUUID().toString()); + newItem.setBookId(bookId); + newItem.setQuantity(context.getQuantity()); + order.getItems().add(newItem); + + Orders updatedOrder = adminService.run(Update.entity(ORDERS).data(order)).single(Orders.class); + messages.success(MessageKeys.BOOK_ADDED_ORDER); + context.setResult(updatedOrder); + } + + /** + * @return the static CSV singleton upload entity + */ + @On(entity = Upload_.CDS_NAME, event = CqnService.EVENT_READ) + public Upload getUploadSingleton() { + return Upload.create(); + } + + /** + * Handles CSV uploads with book data + * @param context + * @param csv + */ + @On + public void addBooksViaCsv(CdsUpdateEventContext context, Upload upload) { + InputStream is = upload.getCsv(); + if (is != null) { + try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) { + br.lines().skip(1).forEach((line) -> { + String[] p = line.split(";"); + Books book = Books.create(); + book.setId(p[0]); + book.setTitle(p[1]); + book.setDescr(p[2]); + book.setAuthorId(p[3]); + book.setStock(Integer.valueOf(p[4]).intValue()); + book.setPrice(BigDecimal.valueOf(Double.valueOf(p[5]))); + book.setCurrencyCode(p[6]); + book.setGenreId(Integer.valueOf(p[7])); + + // separate transaction per line + context.getCdsRuntime().changeSetContext().run(ctx -> { + db.run(Upsert.into(BOOKS).entry(book)); + }); + }); + } catch (IOException e) { + throw new ServiceException(ErrorStatuses.SERVER_ERROR, MessageKeys.BOOK_IMPORT_FAILED, e); + } catch (IndexOutOfBoundsException e) { + throw new ServiceException(ErrorStatuses.SERVER_ERROR, MessageKeys.BOOK_IMPORT_INVALID_CSV, e); + } + } + context.setResult(Arrays.asList(upload)); + } + + private Supplier notFound(String message) { + return () -> new ServiceException(ErrorStatuses.NOT_FOUND, message); + } + + private BigDecimal defaultZero(BigDecimal decimal) { + return decimal == null ? BigDecimal.valueOf(0) : decimal; + } + + /** + * Creates an attachment directly in the active entity state (bypassing draft flow). + * Triggered by the "Create Attachment" button visible only in active entity state. + */ + @On(event = "createAttachmentInActive") + public void createAttachmentInActive(EventContext context) { + String targetEntity = context.getTarget().getQualifiedName(); + logger.info("=== createAttachmentInActive triggered for entity: {} ===", targetEntity); + + // Guard: Skip framework-triggered invocations during edit+save. + // User clicks send "in" as null/empty (RequiresSelection: false). + Object inParam = context.get("in"); + if (inParam instanceof java.util.List && !((java.util.List) inParam).isEmpty()) { + logger.info("Skipping createAttachmentInActive — framework save, not user click"); + context.setCompleted(); + return; + } + + try { + CqnSelect cqn = (CqnSelect) context.get("cqn"); + Map rootKeys = analyzer.analyze(cqn).rootKeys(); + logger.info("Root keys: {}", rootKeys); + + String parentId = extractParentId(cqn, rootKeys); + + if (parentId == null || parentId.isEmpty()) { + logger.error("Could not extract parent ID from CQN. Root keys: {}", rootKeys); + throw new ServiceException(ErrorStatuses.BAD_REQUEST, "Parent entity ID is required to create attachment."); + } + + logger.info("Creating attachment for parent ID: {} in facet: {}", parentId, targetEntity); + + String attachmentId = UUID.randomUUID().toString(); + String timestamp = DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss-SSS") + .withZone(ZoneId.systemDefault()) + .format(Instant.now()); + String fileName = "attachment-" + timestamp + ".txt"; + + String sampleContent = "Sample Attachment\nCreated: " + Instant.now() + + "\nParent ID: " + parentId + + "\nFacet: " + targetEntity; + + InputStream contentStream = new ByteArrayInputStream( + sampleContent.getBytes(StandardCharsets.UTF_8)); + + Map attachmentData = new HashMap<>(); + attachmentData.put("ID", attachmentId); + attachmentData.put("up__ID", parentId); + attachmentData.put("fileName", fileName); + attachmentData.put("mimeType", "text/plain"); + attachmentData.put("note", "Created in active entity"); + attachmentData.put("content", contentStream); + + adminService.run(Insert.into(targetEntity).entry(attachmentData)); + logger.info("Attachment created with ID: {}", attachmentId); + + context.setCompleted(); + + } catch (ServiceException e) { + throw e; + } catch (Exception e) { + logger.error("Failed to create attachment: {}", e.getMessage(), e); + context.setCompleted(); + throw new ServiceException(ErrorStatuses.SERVER_ERROR, "Failed to create attachment: " + e.getMessage(), e); + } + } + + private String extractParentId(CqnSelect cqn, Map rootKeys) { + // Case 1: Direct entity — rootKeys has up__ID + Object upId = rootKeys.get("up__ID"); + if (upId != null) { + return upId.toString(); + } + + // Case 2: Nested composition path — traverse CQN segments + try { + if (cqn.from().isRef()) { + CqnStructuredTypeRef ref = cqn.from().asRef(); + java.util.List segments = ref.segments(); + if (segments.size() >= 2) { + CqnReference.Segment parentSegment = segments.get(segments.size() - 2); + if (parentSegment.filter().isPresent()) { + String parentId = extractIdFromPredicate(parentSegment.filter().get()); + if (parentId != null) return parentId; + } + } + } + } catch (Exception e) { + logger.warn("Could not extract parent ID from CQN path: {}", e.getMessage()); + } + + // Fallback + Object id = rootKeys.get("ID"); + return id != null ? id.toString() : null; + } + + private String extractIdFromPredicate(CqnPredicate predicate) { + if (predicate instanceof CqnComparisonPredicate) { + CqnComparisonPredicate comp = (CqnComparisonPredicate) predicate; + if (comp.left() instanceof CqnElementRef && comp.right() instanceof CqnLiteral) { + String fieldName = ((CqnElementRef) comp.left()).lastSegment(); + if ("ID".equals(fieldName)) { + return ((CqnLiteral) comp.right()).value().toString(); + } + } + } else if (predicate instanceof CqnConnectivePredicate) { + for (CqnPredicate child : ((CqnConnectivePredicate) predicate).predicates()) { + String id = extractIdFromPredicate(child); + if (id != null) return id; + } + } + return null; + } + +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/BookRatingInitialization.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/BookRatingInitialization.java new file mode 100644 index 000000000..6e482dfd2 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/BookRatingInitialization.java @@ -0,0 +1,31 @@ +package my.bookshop.handlers; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import com.sap.cds.services.application.ApplicationLifecycleService; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.After; +import com.sap.cds.services.handler.annotations.ServiceName; + +import my.bookshop.RatingCalculator; + +/** + * Initializes the book ratings based on their review ratings. + */ +@Component +@Profile("default") +@ServiceName(ApplicationLifecycleService.DEFAULT_NAME) +public class BookRatingInitialization implements EventHandler { + + private RatingCalculator ratingCalculator; + + BookRatingInitialization(RatingCalculator ratingCalculator) { + this.ratingCalculator = ratingCalculator; + } + + @After(event = ApplicationLifecycleService.EVENT_APPLICATION_PREPARED) + public void initBookRatings() { + this.ratingCalculator.initBookRatings(); + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/CatalogServiceHandler.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/CatalogServiceHandler.java new file mode 100644 index 000000000..1eae1a8cc --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/CatalogServiceHandler.java @@ -0,0 +1,194 @@ +package my.bookshop.handlers; + +import static cds.gen.catalogservice.CatalogService_.BOOKS; +import static cds.gen.catalogservice.CatalogService_.REVIEWS; + +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.springframework.stereotype.Component; + +import com.sap.cds.Result; +import com.sap.cds.Struct; +import com.sap.cds.ql.Insert; +import com.sap.cds.ql.Select; +import com.sap.cds.ql.Update; +import com.sap.cds.ql.cqn.CqnAnalyzer; +import com.sap.cds.ql.cqn.CqnSelect; +import com.sap.cds.reflect.CdsModel; +import com.sap.cds.services.ErrorStatuses; +import com.sap.cds.services.ServiceException; +import com.sap.cds.services.cds.CdsReadEventContext; +import com.sap.cds.services.cds.CqnService; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.After; +import com.sap.cds.services.handler.annotations.Before; +import com.sap.cds.services.handler.annotations.On; +import com.sap.cds.services.handler.annotations.ServiceName; +import com.sap.cds.services.messages.Messages; +import com.sap.cds.services.persistence.PersistenceService; +import com.sap.cds.services.request.FeatureTogglesInfo; + +import cds.gen.catalogservice.BooksAddReviewContext; +import cds.gen.catalogservice.Books; +import cds.gen.catalogservice.Books_; +import cds.gen.catalogservice.CatalogService_; +import cds.gen.catalogservice.Reviews; +import cds.gen.catalogservice.SubmitOrderContext; +import cds.gen.reviewservice.ReviewService; +import cds.gen.reviewservice.ReviewService_; +import my.bookshop.MessageKeys; +import my.bookshop.RatingCalculator; + +/** + * Custom business logic for the "Catalog Service" (see cat-service.cds) + * + * Handles Reading of Books + * + * Adds Discount Message to the Book Title if too much stock is available + * + * Provides adding book reviews + */ +@Component +@ServiceName(CatalogService_.CDS_NAME) +class CatalogServiceHandler implements EventHandler { + + private final PersistenceService db; + private final ReviewService reviewService; + + private final Messages messages; + private final FeatureTogglesInfo featureToggles; + private final RatingCalculator ratingCalculator; + private final CqnAnalyzer analyzer; + + CatalogServiceHandler(PersistenceService db, ReviewService reviewService, Messages messages, + FeatureTogglesInfo featureToggles, RatingCalculator ratingCalculator, CdsModel model) { + this.db = db; + this.reviewService = reviewService; + this.messages = messages; + this.featureToggles = featureToggles; + this.ratingCalculator = ratingCalculator; + this.analyzer = CqnAnalyzer.create(model); + } + + /** + * Invokes some validations before creating a review. + * + * @param context {@link ReviewContext} + */ + @Before(entity = Books_.CDS_NAME) + public void beforeAddReview(BooksAddReviewContext context) { + String user = context.getUserInfo().getName(); + String bookId = (String) analyzer.analyze(context.getCqn()).targetKeys().get(Books.ID); + + Result result = db.run(Select.from(REVIEWS) + .where(review -> review.book_ID().eq(bookId).and(review.createdBy().eq(user)))); + + if (result.first().isPresent()) { + throw new ServiceException(ErrorStatuses.METHOD_NOT_ALLOWED, MessageKeys.REVIEW_ADD_FORBIDDEN) + .messageTarget(REVIEWS, r -> r.createdBy()); + } + } + + /** + * Handles the review creation from the given context. + * + * @param context {@link ReviewContext} + */ + @On(entity = Books_.CDS_NAME) + public void onAddReview(BooksAddReviewContext context) { + String bookId = (String) analyzer.analyze(context.getCqn()).targetKeys().get(Books.ID); + cds.gen.reviewservice.Reviews review = cds.gen.reviewservice.Reviews.create(); + review.setBookId(bookId); + review.setRating(context.getRating()); + review.setTitle(context.getTitle()); + review.setText(context.getText()); + + Result res = reviewService.run(Insert.into(ReviewService_.REVIEWS).entry(review)); + cds.gen.reviewservice.Reviews inserted = res.single(cds.gen.reviewservice.Reviews.class); + + messages.success(MessageKeys.REVIEW_ADDED); + context.setResult(Struct.access(inserted).as(Reviews.class)); + } + + /** + * Recalculates and sets the book rating after a new review for the given book. + * + * @param context {@link ReviewContext} + */ + @After(entity = Books_.CDS_NAME) + public void afterAddReview(BooksAddReviewContext context) { + ratingCalculator.setBookRating(context.getResult().getBookId()); + } + + @After(event = CqnService.EVENT_READ) + public void discountBooks(Stream books) { + books.filter(b -> b.getTitle() != null).forEach(b -> { + loadStockIfNotSet(b); + discountBooksWithMoreThan111Stock(b, featureToggles.isEnabled("discount")); + }); + } + + @After + public void setIsReviewable(CdsReadEventContext context, List books) { + String user = context.getUserInfo().getName(); + List bookIds = books.stream().filter(b -> b.getId() != null).map(b -> b.getId()) + .collect(Collectors.toList()); + + if (bookIds.isEmpty()) { + return; + } + + CqnSelect query = Select.from(BOOKS, b -> b.filter(b.ID().in(bookIds)).reviews()) + .where(r -> r.createdBy().eq(user)); + + Set reviewedBooks = db.run(query).streamOf(Reviews.class).map(Reviews::getBookId) + .collect(Collectors.toSet()); + + for (Books book : books) { + if (reviewedBooks.contains(book.getId())) { + book.setIsReviewable(false); + } + } + } + + @On + public void onSubmitOrder(SubmitOrderContext context) { + Integer quantity = context.getQuantity(); + String bookId = context.getBook(); + + Optional book = db.run(Select.from(BOOKS).columns(Books_::stock).byId(bookId)).first(Books.class); + + book.orElseThrow(() -> new ServiceException(ErrorStatuses.NOT_FOUND, MessageKeys.BOOK_MISSING) + .messageTarget(BOOKS, b -> b.ID())); + + int stock = book.map(Books::getStock).get(); + + if (stock >= quantity) { + db.run(Update.entity(BOOKS).byId(bookId).data(Books.STOCK, stock -= quantity)); + + SubmitOrderContext.ReturnType result = SubmitOrderContext.ReturnType.create(); + result.setStock(stock); + + context.setResult(result); + } else { + throw new ServiceException(ErrorStatuses.CONFLICT, MessageKeys.ORDER_EXCEEDS_STOCK, quantity); + } + } + + private void discountBooksWithMoreThan111Stock(Books b, boolean premium) { + if (b.getStock() != null && b.getStock() > 111) { + b.setTitle(String.format("%s -- %s%% discount", b.getTitle(), premium ? 14 : 11)); + } + } + + private void loadStockIfNotSet(Books b) { + if (b.getId() != null && b.getStock() == null) { + b.setStock(db.run(Select.from(BOOKS).byId(b.getId()).columns(Books_::stock)).single(Books.class).getStock()); + } + } + +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/DependencyExit.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/DependencyExit.java new file mode 100644 index 000000000..2bdd059a5 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/DependencyExit.java @@ -0,0 +1,104 @@ +package my.bookshop.handlers; + +import java.io.UnsupportedEncodingException; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.sap.cds.Struct; +import com.sap.cds.sdm.model.Repository; +import com.sap.cds.sdm.model.RepositoryParams; +import com.sap.cds.sdm.service.SDMAdminService; +import com.sap.cds.sdm.service.SDMAdminServiceImpl; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.After; +import com.sap.cds.services.handler.annotations.On; +import com.sap.cds.services.handler.annotations.ServiceName; +import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; +import com.sap.cds.services.mt.*; +import com.sap.cloud.environment.servicebinding.api.ServiceBinding; + +import java.util.*; +@Component +@ServiceName(DeploymentService.DEFAULT_NAME) +class DependencyExit implements EventHandler { + + @On(event = DeploymentService.EVENT_DEPENDENCIES) + public void onGetDependencies(DependenciesEventContext context) { + + List dependencies = new ArrayList<>(); + Map uaa = (Map) getSDMCredentials().get("uaa"); + dependencies.add(SaasRegistryDependency.create(uaa.get("xsappname").toString())); + context.setResult(dependencies); + } + private Map getSDMCredentials() { + List allServiceBindings = + DefaultServiceBindingAccessor.getInstance().getServiceBindings(); +// filter for a specific binding +ServiceBinding sdmBinding = + allServiceBindings.stream() + .filter(binding -> "sdm".equalsIgnoreCase(binding.getServiceName().orElse(null))) + .findFirst() + .get(); +return sdmBinding.getCredentials(); + + } + + @After(event = DeploymentService.EVENT_SUBSCRIBE) + public void onSubscribe(SubscribeEventContext context) throws JsonProcessingException,UnsupportedEncodingException { + //use httpclient and onboard a repository + System.out.println("After subscribing to my CAP application"); + final SaasRegistrySubscriptionOptions options = Struct + .access(context.getOptions()) + .as(SaasRegistrySubscriptionOptions.class); + + // Access the specific property + final String subdomain = options.getSubscribedSubdomain(); +SDMAdminService sdmAdminService = new SDMAdminServiceImpl(); + +Repository repository = new Repository(); +repository.setDescription("Onboarding Repo Demo"); +repository.setDisplayName(" Test Onboarding repo"); +repository.setSubdomain(subdomain); +repository.setHashAlgorithms("SHA-256"); +repository.setIsEncryptionEnabled(false); +repository.setIsVirusScanEnabled(false); +repository.setExternalId("MULTITENANT-TEST-REPO"); +List repositoryParams = new ArrayList<>(); +RepositoryParams repositoryParam = new RepositoryParams(); + repositoryParam.setParamName("fileExtensions"); + JsonObject fileExtensionsValue = new JsonObject(); + fileExtensionsValue.addProperty("type", "block"); + fileExtensionsValue.add( + "list", new Gson().toJsonTree(new String[] {"docx","pptx","rtf"})); + + // Convert the nested JSON object to a JSON string + String jsonParamValue = fileExtensionsValue.toString(); + repositoryParam.setParamValue(jsonParamValue); + repositoryParams.add(repositoryParam); + repository.setRepositoryParams(repositoryParams); + repository.setIsVersionEnabled(false); + System.out.println("Repo Param "+repositoryParams); + System.out.println("Repo "+repository); +String response = sdmAdminService.onboardRepository(repository); +System.out.println("Onboard response "+response); + } + + @After(event = DeploymentService.EVENT_UNSUBSCRIBE) + public void afterUnsubscribe(UnsubscribeEventContext context) { + //delete onboarded repository + System.out.println("After unsubscribing to my CAP application"); + final SaasRegistrySubscriptionOptions options = Struct + .access(context.getOptions()) + .as(SaasRegistrySubscriptionOptions.class); + // Access the specific property + final String subdomain = options.getSubscribedSubdomain(); + System.out.println("subdomain "+subdomain); + + SDMAdminService sdmAdminService = new SDMAdminServiceImpl(); + String res = sdmAdminService.offboardRepository(subdomain); + System.out.println(res); + } + +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/NotesServiceHandler.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/NotesServiceHandler.java new file mode 100644 index 000000000..26d9a2e9d --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/NotesServiceHandler.java @@ -0,0 +1,208 @@ +package my.bookshop.handlers; + +import static cds.gen.notesservice.NotesService_.ADDRESSES; +import static cds.gen.notesservice.NotesService_.NOTES; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import com.sap.cds.Result; +import com.sap.cds.ql.CQL; +import com.sap.cds.ql.Predicate; +import com.sap.cds.ql.Select; +import com.sap.cds.ql.cqn.CqnAnalyzer; +import com.sap.cds.ql.cqn.CqnExpand; +import com.sap.cds.ql.cqn.CqnPredicate; +import com.sap.cds.ql.cqn.CqnReference.Segment; +import com.sap.cds.ql.cqn.CqnSelect; +import com.sap.cds.ql.cqn.CqnSelectListItem; +import com.sap.cds.ql.cqn.CqnStructuredTypeRef; +import com.sap.cds.ql.cqn.Modifier; +import com.sap.cds.reflect.CdsModel; +import com.sap.cds.services.cds.CdsReadEventContext; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.On; +import com.sap.cds.services.handler.annotations.ServiceName; + +import cds.gen.api_business_partner.ApiBusinessPartner; +import cds.gen.api_business_partner.ApiBusinessPartner_; +import cds.gen.notesservice.Addresses; +import cds.gen.notesservice.Addresses_; +import cds.gen.notesservice.Notes; +import cds.gen.notesservice.NotesService_; +import cds.gen.notesservice.Notes_; + +@Component +@ServiceName(NotesService_.CDS_NAME) +public class NotesServiceHandler implements EventHandler { + + private final ApiBusinessPartner bupa; + private final CqnAnalyzer analyzer; + + NotesServiceHandler(@Qualifier(ApiBusinessPartner_.CDS_NAME) ApiBusinessPartner bupa, CdsModel model) { + this.bupa = bupa; + this.analyzer = CqnAnalyzer.create(model); + } + + @On(entity = Addresses_.CDS_NAME) + Result readAddresses(CdsReadEventContext context) { + List segments = context.getCqn().ref().segments(); + // via note + if(segments.size() == 2 && segments.get(0).id().equals(Notes_.CDS_NAME)) { + Map noteKeys = analyzer.analyze(context.getCqn()).rootKeys(); + Notes note = context.getService().run(Select.from(NOTES).columns(n -> n.address_businessPartner(), n -> n.address_ID()).matching(noteKeys)).single(Notes.class); + CqnSelect addressOfNote = CQL.copy(context.getCqn(), new Modifier() { + + @Override + public CqnStructuredTypeRef ref(CqnStructuredTypeRef ref) { + return CQL.entity(Addresses_.CDS_NAME) + .filter(p -> p.get(Addresses.BUSINESS_PARTNER).eq(note.getAddressBusinessPartner()) + .and(p.get(Addresses.ID).eq(note.getAddressId()))) + .asRef(); + } + + }); + return context.getService().run(addressOfNote); + } + + // notes expanded? + AtomicReference notesExpandHolder = new AtomicReference<>(); + CqnSelect noNotesExpand = CQL.copy(context.getCqn(), new Modifier() { + + public List items(List items) { + notesExpandHolder.set(removeIfExpanded(items, Addresses.NOTES)); + return ensureSelected(items, Addresses.BUSINESS_PARTNER, Addresses.ID); + } + + }); + + // read addresses + Result addresses = bupa.run(noNotesExpand); + + // add expanded notes? + CqnExpand notesExpand = notesExpandHolder.get(); + if(notesExpand != null) { + Select notesSelect = Select.from(NOTES) + .columns(ensureSelected(notesExpand.items(), Notes.ADDRESS_BUSINESS_PARTNER, Notes.ADDRESS_ID)) + .orderBy(notesExpand.orderBy()) + .where(n -> CQL.or(addresses.streamOf(Addresses.class) + .map(address -> n.address_businessPartner().eq(address.getBusinessPartner()).and(n.address_ID().eq(address.getId()))) + .collect(Collectors.toList())) + .and(predicate(notesExpand.ref().rootSegment()))); + + Result notes = context.getService().run(notesSelect); + for(Addresses address : addresses.listOf(Addresses.class)) { + address.setNotes( + notes.streamOf(Notes.class) + .filter(n -> n.getAddressBusinessPartner().equals(address.getBusinessPartner()) + && n.getAddressId().equals(address.getId())) + .collect(Collectors.toList())); + } + } + + return addresses; + } + + @On(entity = Notes_.CDS_NAME) + void readNotes(CdsReadEventContext context) { + List segments = context.getCqn().ref().segments(); + // via addresses + if(segments.size() == 2 && segments.get(0).id().equals(Addresses_.CDS_NAME)) { + Map addressKeys = analyzer.analyze(context.getCqn()).rootKeys(); + CqnSelect notesOfAddress = CQL.copy(context.getCqn(), new Modifier() { + + @Override + public CqnStructuredTypeRef ref(CqnStructuredTypeRef ref) { + return CQL.entity(Notes_.CDS_NAME).filter(predicate(segments.get(1))).asRef(); + } + + @Override + public Predicate where(Predicate where) { + Predicate ofAddress = CQL.get(Notes.ADDRESS_BUSINESS_PARTNER).eq(addressKeys.get(Addresses.BUSINESS_PARTNER)) + .and(CQL.get(Notes.ADDRESS_ID).eq(addressKeys.get(Addresses.ID))); + if(where != null) { + ofAddress = ofAddress.and(where); + } + return ofAddress; + } + + }); + context.setResult(context.getService().run(notesOfAddress)); + return; + } + + // address expanded? + AtomicReference addressExpandHolder = new AtomicReference<>(); + CqnSelect noAddressExpand = CQL.copy(context.getCqn(), new Modifier() { + + public List items(List items) { + addressExpandHolder.set(removeIfExpanded(items, Notes.ADDRESS)); + return ensureSelected(items, Notes.ADDRESS_BUSINESS_PARTNER, Notes.ADDRESS_ID); + } + + }); + + CqnExpand addressExpand = addressExpandHolder.get(); + if(addressExpand != null) { + // read notes and join with addresses + Result notes = context.getService().run(noAddressExpand); + List notesWithAddresses = notes.streamOf(Notes.class).filter(n -> n.getAddressBusinessPartner() != null && n.getAddressId() != null).collect(Collectors.toList()); + if (notesWithAddresses.size() > 0) { + Select addressSelect = Select.from(ADDRESSES) + .columns(ensureSelected(addressExpand.items(), Addresses.BUSINESS_PARTNER, Addresses.ID)) + .orderBy(addressExpand.orderBy()) + .where(a -> CQL.or(notesWithAddresses.stream() + .map(n -> a.businessPartner().eq(n.getAddressBusinessPartner()).and(a.ID().eq(n.getAddressId()))) + .collect(Collectors.toList())) + .and(predicate(addressExpand.ref().rootSegment()))); + + Result addresses = context.getService().run(addressSelect); + for(Notes note : notes.listOf(Notes.class)) { + note.setAddress(addresses.streamOf(Addresses.class) + .filter(a -> a.getBusinessPartner().equals(note.getAddressBusinessPartner()) + && a.getId().equals(note.getAddressId())) + .findFirst().orElse(null)); + } + } + context.setResult(notes); + return; + } + } + + private CqnExpand removeIfExpanded(List items, String association) { + CqnExpand expanded = items.stream().filter(i -> i.isExpand()).map(i -> i.asExpand()) + .filter(i -> i.ref().firstSegment().equals(association)).findFirst().orElse(null); + if(expanded != null) { + items.remove(expanded); + } + return expanded; + } + + private List ensureSelected(List items, String... elements) { + if(items.stream().anyMatch(i -> i.isStar())) { + return items; + } + Set newElements = new HashSet<>(); + for(String element : elements) { + if(!items.stream().anyMatch(i -> i.isValue() && i.asValue().displayName().equals(element))) { + newElements.add(element); + } + } + List newItems = new ArrayList<>(items); + newElements.forEach(element -> newItems.add(CQL.get(element))); + return newItems; + } + + private CqnPredicate predicate(Segment segment) { + return segment.filter().orElse(CQL.constant(true).eq(true)); + } + +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/OnboardRepository.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/OnboardRepository.java new file mode 100644 index 000000000..3ce44b240 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/OnboardRepository.java @@ -0,0 +1,14 @@ +package my.bookshop.handlers; + +public class OnboardRepository { + private Repository repository; + + public Repository getRepository() { + return repository; + } + + public void setRepository(Repository repository) { + this.repository = repository; + } + +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/Repository.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/Repository.java new file mode 100644 index 000000000..0fa1c335b --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/Repository.java @@ -0,0 +1,36 @@ +package my.bookshop.handlers; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class Repository { + private String displayName; + private String externalId; + private String description; + private String repositoryId; +public String getDisplayName() { + return displayName; +} +public void setDisplayName(String displayName) { + this.displayName = displayName; +} +public String getExternalId() { + return externalId; +} +public void setExternalId(String externalId) { + this.externalId = externalId; +} +public String getDescription() { + return description; +} +public void setDescription(String description) { + this.description = description; +} +public String getRepositoryId() { + return repositoryId; +} +public void setRepositoryId(String repositoryId) { + this.repositoryId = repositoryId; +} + +} + diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/SubscriptionHandler.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/SubscriptionHandler.java new file mode 100644 index 000000000..8b70715fb --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/SubscriptionHandler.java @@ -0,0 +1,33 @@ +package my.bookshop.handlers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import com.sap.cds.services.auditlog.AuditLogService; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.After; +import com.sap.cds.services.handler.annotations.ServiceName; +import com.sap.cds.services.mt.DeploymentService; +import com.sap.cds.services.mt.SubscribeEventContext; + +/** + * Handler that implements subscription logic + */ +@Component +@Profile("cloud") +@ServiceName(DeploymentService.DEFAULT_NAME) +class SubscriptionHandler implements EventHandler { + + @Autowired + private AuditLogService auditLog; + + @After + public void afterSubscribe(SubscribeEventContext context) { + String msg = String.format("New tenant '%s' subscribed.", context.getTenant()); + + // send audit log security message to provider tenant as user's tenant is null + auditLog.logSecurityEvent("tenant subscribed", msg); + } + +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/external/ApiBusinessPartnerEventMockHandler.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/external/ApiBusinessPartnerEventMockHandler.java new file mode 100644 index 000000000..2a353754f --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/handlers/external/ApiBusinessPartnerEventMockHandler.java @@ -0,0 +1,50 @@ +package my.bookshop.handlers.external; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import com.sap.cds.ql.cqn.CqnAnalyzer; +import com.sap.cds.services.cds.ApplicationService; +import com.sap.cds.services.cds.CdsUpdateEventContext; +import com.sap.cds.services.cds.CqnService; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.After; +import com.sap.cds.services.handler.annotations.ServiceName; + +import cds.gen.api_business_partner.ABusinessPartnerAddress; +import cds.gen.api_business_partner.ABusinessPartnerAddress_; +import cds.gen.api_business_partner.ApiBusinessPartner_; +import cds.gen.api_business_partner.BusinessPartnerChanged; +import cds.gen.api_business_partner.BusinessPartnerChangedContext; + +/** + * This class mocks the event emitting of the S/4 API + */ +@Component +@Profile("!cloud") +@ServiceName(value = { ApiBusinessPartner_.CDS_NAME, "api-business-partner-mocked"}, type = ApplicationService.class) +public class ApiBusinessPartnerEventMockHandler implements EventHandler { + + private final static Logger logger = LoggerFactory.getLogger(ApiBusinessPartnerEventMockHandler.class); + + @After(event = CqnService.EVENT_UPDATE, entity = ABusinessPartnerAddress_.CDS_NAME) + public void businessPartnerChanged(CdsUpdateEventContext context) { + // Get BusinessPartner ID + CqnAnalyzer analyzer = CqnAnalyzer.create(context.getModel()); + String businessPartner = (String) analyzer.analyze(context.getCqn().ref()).targetKeys().get(ABusinessPartnerAddress.BUSINESS_PARTNER); + + // Construct S/4 HANA Payload + BusinessPartnerChanged payload = BusinessPartnerChanged.create(); + payload.setBusinessPartner(businessPartner); + + // Emit Changed Event + logger.info("<< emitting: " + payload); + BusinessPartnerChangedContext changed = BusinessPartnerChangedContext.create(); + changed.setData(payload); + context.getService().emit(changed); + } + + +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/health/AppActuator.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/health/AppActuator.java new file mode 100644 index 000000000..e661e1f4f --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/health/AppActuator.java @@ -0,0 +1,27 @@ +package my.bookshop.health; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; +import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.stereotype.Component; + + +/** + * Custom app actuator implementation. + */ +@Component +@ConditionalOnClass(Endpoint.class) +@Endpoint(id = "bookshop", enableByDefault = true) +public class AppActuator { + + @ReadOperation + public Map info() { + Map info = new LinkedHashMap<>(); + info.put("Version", "1.0.0"); + return info; + } + +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/health/CustomHealthIndicator.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/health/CustomHealthIndicator.java new file mode 100644 index 000000000..ba702f7f7 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/java/my/bookshop/health/CustomHealthIndicator.java @@ -0,0 +1,28 @@ +package my.bookshop.health; + +import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.stereotype.Component; + +/** + * Custom health indicator implementation. + */ +@Component("myhealth") +@ConditionalOnEnabledHealthIndicator("myhealth") +public class CustomHealthIndicator implements HealthIndicator { + + @Override + public Health health() { + if (check() != 0) { + return Health.down().build(); + } + return Health.up().build(); + } + + private int check() { + // perform some health check + return 0; + } + +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/META-INF/native-image/resource-config.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/META-INF/native-image/resource-config.json new file mode 100644 index 000000000..5eb7cfcad --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/META-INF/native-image/resource-config.json @@ -0,0 +1,12 @@ +{ + "resources": { + "includes": [ + { + "pattern": "\\Qmessages.properties\\E" + }, + { + "pattern": "\\Qmessages_de.properties\\E" + } + ] + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/application.yaml b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/application.yaml new file mode 100644 index 000000000..b956b4b62 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/application.yaml @@ -0,0 +1,136 @@ +--- +logging: + level: + '[com.sap.cds.auditlog]': DEBUG +spring: + jmx: + enabled: true +cds: + odata-v4: + endpoint.path: "/api" + lazy-i18n.enabled: true + multi-tenancy: + compatibility.enabled: false + mtxs.enabled: true + security: + authentication.normalize-provider-tenant: true + mock.users: + admin: + password: admin + roles: + - admin + attributes: + businessPartner: + - "10401010" + user: + password: user +server.servlet.encoding: + charset: UTF-8 + force: true +management: + endpoint: + health: + show-components: always + show-details: always + endpoints: + web: + exposure: + include: "health" + health: + defaults.enabled: false + ping.enabled: true + db.enabled: true + myhealth.enabled: true + +--- +spring: + config.activate.on-profile: cloud + sql.init.schema-locations: "classpath:schema-nomocks.sql" +cds: + sql.hana: + optimizationMode: hex + search: + fuzzy: true + fuzzinessThreshold: 0.9 + messaging.services: + bupa-messaging: + kind: enterprise-messaging + format: cloudevents + subscribe-prefix: sap/S4HANAOD/java/ce/ + +--- +spring: + config.activate.on-profile: sandbox +cds: + remote.services: + '[API_BUSINESS_PARTNER]': + type: "odata-v2" + http: + headers: + APIKey: "" # Place API Key from SAP API Business Hub here or use environment variable CDS_REMOTE_SERVICES_API_BUSINESS_PARTNER_HTTP_HEADERS_APIKEY + destination: + properties: + url: "https://sandbox.api.sap.com/s4hanacloud/sap/opu/odata/sap" + +--- +spring: + config.activate.on-profile: destination +cds: + remote.services: + '[API_BUSINESS_PARTNER]': + type: "odata-v2" + http: + suffix: "/sap/opu/odata/sap" + destination: + name: "s4-destination" + +--- +spring: + config.activate.on-profile: mocked +cds: + messaging.services: + bupa-messaging: + kind: file-based-messaging + application.services: + api-business-partner-mocked: + model: API_BUSINESS_PARTNER + serve: + path: API_BUSINESS_PARTNER + remote.services: + '[API_BUSINESS_PARTNER]': + http: + suffix: "/api" + destination: + name: "myself" + +--- +spring: + config.activate.on-profile: ft +cds: + model.provider.url: http://localhost:4005 + security.mock.users: + admin: + features: + - isbn + - discount + user: + features: + - isbn + +--- +spring: + config.activate.on-profile: local-mtxs +cds: + multi-tenancy.sidecar.url: http://localhost:4005 + security.mock.users: + admin: + tenant: t1 + user: + tenant: t1 + +--- +spring: + config.activate.on-profile: default +cds: + data-source: + auto-config.enabled: false diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/logback-spring.xml b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/logback-spring.xml new file mode 100644 index 000000000..bef4441a1 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/logback-spring.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/messages.properties b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/messages.properties new file mode 100644 index 000000000..67a07e3fa --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/messages.properties @@ -0,0 +1,14 @@ +quantity.require.minimum = The specified quantity is smaller than 1 +book.require.stock = Not enough books on stock (only {0} left) +book.added.order = Book successfully added to order +book.missing = Book does not exist +orderitem.missing = OrderItem does not exist +order.missing = Order does not exist +order.indraft = Order is currently in draft mode +bupa.missing = No Business Parter for this user available +review.added = Review added +order.exceeds.stock = {0} exceeds stock for book +review.add.forbidden=User not allowed to add more than one review for a given book +book.import.failed = Import of books failed +book.import.invalid.csv = Invalid CSV structure found - Please check its content +SDM.Attachments.maxCountError = Maximum number of attachments reached in English diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/messages_de.properties b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/messages_de.properties new file mode 100644 index 000000000..f498bbe00 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/messages_de.properties @@ -0,0 +1,13 @@ +quantity.require.minimum = Die eingetragene Anzahl ist kleiner als 1 +book.require.stock = Nicht genügend Bücher auf Vorrat (nur {0} übrig) +book.added.order = Das Buch wurde der Bestellung erfolgreich hinzugefügt +book.missing = Das Buch existiert nicht +orderitem.missing = Der Bestellungseintrag existiert nicht +order.missing = Die Bestellung existiert nicht +order.indraft = Die Bestellung ist bereits in Bearbeitung +bupa.missing = Kein Business Parter für diesen User verfügbar +review.added = Bewertung hinzugefügt +order.exceeds.stock = {0} ist mehr als für das Buch auf Vorrat übrig ist +review.add.forbidden = Es ist nicht mehr als eine Bewertung pro Buch erlaubt +book.import.failed = Bücher Import fehlgeschlagen +book.import.invalid.csv = Die CSV Datei enthält eine ungültige Struktur - Bitte überprüfen Sie den Inhalt \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/schema-nomocks.sql b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/schema-nomocks.sql new file mode 100644 index 000000000..dc0c09419 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/schema-nomocks.sql @@ -0,0 +1,1270 @@ + +DROP VIEW IF EXISTS localized_AdminService_Orders_changes; +DROP VIEW IF EXISTS localized_AdminService_Orders; +DROP VIEW IF EXISTS localized_ReviewService_Books_attachments; +DROP VIEW IF EXISTS localized_ReviewService_Authors; +DROP VIEW IF EXISTS localized_ReviewService_Reviews; +DROP VIEW IF EXISTS localized_CatalogService_Books_attachments; +DROP VIEW IF EXISTS localized_CatalogService_Reviews; +DROP VIEW IF EXISTS localized_CatalogService_Authors; +DROP VIEW IF EXISTS localized_AdminService_OrderItems; +DROP VIEW IF EXISTS localized_AdminService_Books_attachments; +DROP VIEW IF EXISTS localized_AdminService_Authors; +DROP VIEW IF EXISTS localized_ReviewService_Statuses; +DROP VIEW IF EXISTS localized_CatalogService_Statuses; +DROP VIEW IF EXISTS localized_AdminService_Statuses; +DROP VIEW IF EXISTS localized_ReviewService_Currencies; +DROP VIEW IF EXISTS localized_ReviewService_Genres; +DROP VIEW IF EXISTS localized_CatalogService_Currencies; +DROP VIEW IF EXISTS localized_CatalogService_Genres; +DROP VIEW IF EXISTS localized_AdminService_Currencies; +DROP VIEW IF EXISTS localized_AdminService_Genres; +DROP VIEW IF EXISTS localized_ReviewService_Books; +DROP VIEW IF EXISTS localized_CatalogService_Books; +DROP VIEW IF EXISTS localized_AdminService_Languages; +DROP VIEW IF EXISTS localized_AdminService_Books; +DROP VIEW IF EXISTS ReviewService_DraftAdministrativeData; +DROP VIEW IF EXISTS NotesService_DraftAdministrativeData; +DROP VIEW IF EXISTS AdminService_DraftAdministrativeData; +DROP VIEW IF EXISTS localized_my_bookshop_Orders_changes; +DROP VIEW IF EXISTS localized_my_bookshop_Books_attachments; +DROP VIEW IF EXISTS localized_my_bookshop_Reviews; +DROP VIEW IF EXISTS localized_my_bookshop_OrderItems; +DROP VIEW IF EXISTS localized_my_bookshop_Orders; +DROP VIEW IF EXISTS localized_my_bookshop_Authors; +DROP VIEW IF EXISTS localized_sap_common_Currencies; +DROP VIEW IF EXISTS localized_sap_common_Languages; +DROP VIEW IF EXISTS localized_my_bookshop_Genres; +DROP VIEW IF EXISTS localized_my_bookshop_Books; +DROP VIEW IF EXISTS localized_Statuses; +DROP VIEW IF EXISTS ReviewService_Statuses_texts; +DROP VIEW IF EXISTS CatalogService_Statuses_texts; +DROP VIEW IF EXISTS AdminService_Statuses_texts; +DROP VIEW IF EXISTS ReviewService_Statuses; +DROP VIEW IF EXISTS ReviewService_Currencies_texts; +DROP VIEW IF EXISTS ReviewService_Genres_texts; +DROP VIEW IF EXISTS CatalogService_Statuses; +DROP VIEW IF EXISTS CatalogService_Currencies_texts; +DROP VIEW IF EXISTS CatalogService_Genres_texts; +DROP VIEW IF EXISTS AdminService_Changes; +DROP VIEW IF EXISTS AdminService_Statuses; +DROP VIEW IF EXISTS AdminService_Currencies_texts; +DROP VIEW IF EXISTS AdminService_Genres_texts; +DROP VIEW IF EXISTS ReviewService_Books_texts; +DROP VIEW IF EXISTS ReviewService_Books_attachments; +DROP VIEW IF EXISTS ReviewService_Currencies; +DROP VIEW IF EXISTS ReviewService_Genres; +DROP VIEW IF EXISTS CatalogService_Books_texts; +DROP VIEW IF EXISTS CatalogService_Books_attachments; +DROP VIEW IF EXISTS CatalogService_Currencies; +DROP VIEW IF EXISTS CatalogService_Genres; +DROP VIEW IF EXISTS AdminService_Languages_texts; +DROP VIEW IF EXISTS AdminService_Addresses; +DROP VIEW IF EXISTS AdminService_Orders_changes; +DROP VIEW IF EXISTS AdminService_OrderItems; +DROP VIEW IF EXISTS AdminService_Books_texts; +DROP VIEW IF EXISTS AdminService_Books_attachments; +DROP VIEW IF EXISTS AdminService_Currencies; +DROP VIEW IF EXISTS AdminService_Genres; +DROP VIEW IF EXISTS ReviewService_Authors; +DROP VIEW IF EXISTS ReviewService_Books; +DROP VIEW IF EXISTS ReviewService_Reviews; +DROP VIEW IF EXISTS NotesService_Notes; +DROP VIEW IF EXISTS CatalogService_Reviews; +DROP VIEW IF EXISTS CatalogService_Authors; +DROP VIEW IF EXISTS CatalogService_Books; +DROP VIEW IF EXISTS AdminService_Languages; +DROP VIEW IF EXISTS AdminService_Orders; +DROP VIEW IF EXISTS AdminService_Authors; +DROP VIEW IF EXISTS AdminService_Books; +DROP TABLE IF EXISTS ReviewService_Reviews_drafts; +DROP TABLE IF EXISTS NotesService_Notes_drafts; +DROP TABLE IF EXISTS AdminService_OrderItems_drafts; +DROP TABLE IF EXISTS AdminService_Orders_drafts; +DROP TABLE IF EXISTS AdminService_Books_texts_drafts; +DROP TABLE IF EXISTS AdminService_Books_attachments_drafts; +DROP TABLE IF EXISTS AdminService_Books_drafts; +DROP TABLE IF EXISTS DRAFT_DraftAdministrativeData; +DROP TABLE IF EXISTS sap_common_Currencies_texts; +DROP TABLE IF EXISTS sap_common_Languages_texts; +DROP TABLE IF EXISTS my_bookshop_Orders_changes; +DROP TABLE IF EXISTS my_bookshop_Genres_texts; +DROP TABLE IF EXISTS my_bookshop_Books_texts; +DROP TABLE IF EXISTS my_bookshop_Books_attachments; +DROP TABLE IF EXISTS Statuses_texts; +DROP TABLE IF EXISTS sap_changelog_Changes; +DROP TABLE IF EXISTS sap_common_Currencies; +DROP TABLE IF EXISTS sap_common_Languages; +DROP TABLE IF EXISTS cds_outbox_Messages; +DROP TABLE IF EXISTS my_bookshop_Notes; +DROP TABLE IF EXISTS my_bookshop_Reviews; +DROP TABLE IF EXISTS my_bookshop_OrderItems; +DROP TABLE IF EXISTS my_bookshop_Orders; +DROP TABLE IF EXISTS my_bookshop_Genres; +DROP TABLE IF EXISTS my_bookshop_Authors; +DROP TABLE IF EXISTS my_bookshop_Books; +DROP TABLE IF EXISTS cds_xt_Extensions; +DROP TABLE IF EXISTS my_bookshop_Addresses; +DROP TABLE IF EXISTS Statuses; + +CREATE TABLE Statuses ( + code NVARCHAR(255) NOT NULL, + text NVARCHAR(255), + PRIMARY KEY(code) +); + +CREATE TABLE my_bookshop_Addresses ( + ID NVARCHAR(10) NOT NULL, + businessPartner NVARCHAR(10) NOT NULL, + country NVARCHAR(3), + city NVARCHAR(40), + postalCode NVARCHAR(10), + street NVARCHAR(60), + houseNumber NVARCHAR(10), + tombstone BOOLEAN, + PRIMARY KEY(ID, businessPartner) +); + +CREATE TABLE cds_xt_Extensions ( + ID NVARCHAR(36) NOT NULL, + tag NVARCHAR(255), + csn NCLOB, + i18n NCLOB, + sources BINARY LARGE OBJECT, + activated NVARCHAR(255), + timestamp TIMESTAMP(7), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Books ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + modifiedAt TIMESTAMP(7), + modifiedBy NVARCHAR(255), + title NVARCHAR(111), + descr NVARCHAR(1111), + author_ID NVARCHAR(36), + genre_ID INTEGER, + stock INTEGER, + price DECIMAL(9, 2), + currency_code NVARCHAR(3), + rating DECIMAL(2, 1), + isReviewable BOOLEAN NOT NULL DEFAULT TRUE, + isbn NVARCHAR(40), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Authors ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + modifiedAt TIMESTAMP(7), + modifiedBy NVARCHAR(255), + name NVARCHAR(111), + dateOfBirth DATE, + dateOfDeath DATE, + placeOfBirth NVARCHAR(255), + placeOfDeath NVARCHAR(255), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Genres ( + name NVARCHAR(255), + descr NVARCHAR(1000), + ID INTEGER NOT NULL, + parent_ID INTEGER, + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Orders ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + modifiedAt TIMESTAMP(7), + modifiedBy NVARCHAR(255), + OrderNo NVARCHAR(255), + buyer NVARCHAR(255), + total DECIMAL(9, 2), + currency_code NVARCHAR(3), + shippingAddress_ID NVARCHAR(10), + shippingAddress_businessPartner NVARCHAR(10), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_OrderItems ( + ID NVARCHAR(36) NOT NULL, + parent_ID NVARCHAR(36), + book_ID NVARCHAR(36), + quantity INTEGER, + amount DECIMAL(9, 2), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Reviews ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + modifiedAt TIMESTAMP(7), + modifiedBy NVARCHAR(255), + book_ID NVARCHAR(36), + rating INTEGER, + title NVARCHAR(111), + text NVARCHAR(1111), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Notes ( + ID NVARCHAR(36) NOT NULL, + note NVARCHAR(255), + address_ID NVARCHAR(10), + address_businessPartner NVARCHAR(10), + PRIMARY KEY(ID) +); + +CREATE TABLE cds_outbox_Messages ( + ID NVARCHAR(36) NOT NULL, + timestamp TIMESTAMP(7), + target NVARCHAR(255), + msg NCLOB, + attempts INTEGER DEFAULT 0, + "PARTITION" INTEGER DEFAULT 0, + lastError NCLOB, + lastAttemptTimestamp TIMESTAMP(7), + PRIMARY KEY(ID) +); + +CREATE TABLE sap_common_Languages ( + name NVARCHAR(255), + descr NVARCHAR(1000), + code NVARCHAR(14) NOT NULL, + PRIMARY KEY(code) +); + +CREATE TABLE sap_common_Currencies ( + name NVARCHAR(255), + descr NVARCHAR(1000), + code NVARCHAR(3) NOT NULL, + symbol NVARCHAR(5), + minorUnit SMALLINT, + PRIMARY KEY(code) +); + +CREATE TABLE sap_changelog_Changes ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + changeLogID NVARCHAR(36), + rootEntity NVARCHAR(255), + rootIdentifier NVARCHAR(255), + attribute NVARCHAR(255), + valueChangedFrom NVARCHAR(5000), + valueChangedTo NVARCHAR(5000), + valueDataType NVARCHAR(255), + targetIdentifier NVARCHAR(255), + targetEntity NVARCHAR(255), + path NVARCHAR(5000), + modification NVARCHAR(255), + PRIMARY KEY(ID) +); + +CREATE TABLE Statuses_texts ( + locale NVARCHAR(14) NOT NULL, + code NVARCHAR(255) NOT NULL, + text NVARCHAR(255), + PRIMARY KEY(locale, code) +); + +CREATE TABLE my_bookshop_Books_attachments ( + up__ID NVARCHAR(36) NOT NULL, + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + modifiedAt TIMESTAMP(7), + modifiedBy NVARCHAR(255), + content BINARY LARGE OBJECT, + mimeType NVARCHAR(255), + fileName NVARCHAR(255), + contentId NVARCHAR(255), + status NVARCHAR(255), + scannedAt TIMESTAMP(7), + note NVARCHAR(255), + folderId NVARCHAR(255), + repositoryId NVARCHAR(255), + objectId NVARCHAR(255), + PRIMARY KEY(up__ID, ID) +); + +CREATE TABLE my_bookshop_Books_texts ( + ID_texts NVARCHAR(36) NOT NULL, + locale NVARCHAR(14), + ID NVARCHAR(36), + title NVARCHAR(111), + descr NVARCHAR(1111), + PRIMARY KEY(ID_texts), + CONSTRAINT my_bookshop_Books_texts_locale UNIQUE (locale, ID) +); + +CREATE TABLE my_bookshop_Genres_texts ( + locale NVARCHAR(14) NOT NULL, + name NVARCHAR(255), + descr NVARCHAR(1000), + ID INTEGER NOT NULL, + PRIMARY KEY(locale, ID) +); + +CREATE TABLE my_bookshop_Orders_changes ( + up__ID NVARCHAR(36) NOT NULL, + change_ID NVARCHAR(36) NOT NULL, + PRIMARY KEY(up__ID, change_ID) +); + +CREATE TABLE sap_common_Languages_texts ( + locale NVARCHAR(14) NOT NULL, + name NVARCHAR(255), + descr NVARCHAR(1000), + code NVARCHAR(14) NOT NULL, + PRIMARY KEY(locale, code) +); + +CREATE TABLE sap_common_Currencies_texts ( + locale NVARCHAR(14) NOT NULL, + name NVARCHAR(255), + descr NVARCHAR(1000), + code NVARCHAR(3) NOT NULL, + PRIMARY KEY(locale, code) +); + +CREATE TABLE DRAFT_DraftAdministrativeData ( + DraftUUID NVARCHAR(36) NOT NULL, + CreationDateTime TIMESTAMP(7), + CreatedByUser NVARCHAR(256), + DraftIsCreatedByMe BOOLEAN, + LastChangeDateTime TIMESTAMP(7), + LastChangedByUser NVARCHAR(256), + InProcessByUser NVARCHAR(256), + DraftIsProcessedByMe BOOLEAN, + PRIMARY KEY(DraftUUID) +); + +CREATE TABLE AdminService_Books_drafts ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7) NULL, + createdBy NVARCHAR(255) NULL, + modifiedAt TIMESTAMP(7) NULL, + modifiedBy NVARCHAR(255) NULL, + title NVARCHAR(111) NULL, + descr NVARCHAR(1111) NULL, + author_ID NVARCHAR(36) NULL, + genre_ID INTEGER NULL, + stock INTEGER NULL, + price DECIMAL(9, 2) NULL, + currency_code NVARCHAR(3) NULL, + rating DECIMAL(2, 1) NULL, + isReviewable BOOLEAN NULL DEFAULT TRUE, + isbn NVARCHAR(40) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID) +); + +CREATE TABLE AdminService_Books_attachments_drafts ( + up__ID NVARCHAR(36) NOT NULL, + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7) NULL, + createdBy NVARCHAR(255) NULL, + modifiedAt TIMESTAMP(7) NULL, + modifiedBy NVARCHAR(255) NULL, + content BINARY LARGE OBJECT NULL, + mimeType NVARCHAR(255) NULL, + fileName NVARCHAR(255) NULL, + contentId NVARCHAR(255) NULL, + status NVARCHAR(255) NULL, + scannedAt TIMESTAMP(7) NULL, + note NVARCHAR(255) NULL, + folderId NVARCHAR(255) NULL, + repositoryId NVARCHAR(255) NULL, + objectId NVARCHAR(255) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(up__ID, ID) +); + +CREATE TABLE AdminService_Books_texts_drafts ( + ID_texts NVARCHAR(36) NOT NULL, + locale NVARCHAR(14) NULL, + ID NVARCHAR(36) NULL, + title NVARCHAR(111) NULL, + descr NVARCHAR(1111) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID_texts) +); + +CREATE TABLE AdminService_Orders_drafts ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7) NULL, + createdBy NVARCHAR(255) NULL, + modifiedAt TIMESTAMP(7) NULL, + modifiedBy NVARCHAR(255) NULL, + OrderNo NVARCHAR(255) NULL, + buyer NVARCHAR(255) NULL, + total DECIMAL(9, 2) NULL, + currency_code NVARCHAR(3) NULL, + shippingAddress_ID NVARCHAR(10) NULL, + shippingAddress_businessPartner NVARCHAR(10) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID) +); + +CREATE TABLE AdminService_OrderItems_drafts ( + ID NVARCHAR(36) NOT NULL, + parent_ID NVARCHAR(36) NULL, + book_ID NVARCHAR(36) NULL, + quantity INTEGER NULL, + amount DECIMAL(9, 2) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID) +); + +CREATE TABLE NotesService_Notes_drafts ( + ID NVARCHAR(36) NOT NULL, + note NVARCHAR(255) NULL, + address_ID NVARCHAR(10) NULL, + address_businessPartner NVARCHAR(10) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID) +); + +CREATE TABLE ReviewService_Reviews_drafts ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7) NULL, + createdBy NVARCHAR(255) NULL, + modifiedAt TIMESTAMP(7) NULL, + modifiedBy NVARCHAR(255) NULL, + book_ID NVARCHAR(36) NULL, + rating INTEGER NULL, + title NVARCHAR(111) NULL, + text NVARCHAR(1111) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID) +); + +CREATE VIEW AdminService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.createdBy, + Books_0.modifiedAt, + Books_0.modifiedBy, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM my_bookshop_Books AS Books_0; + +CREATE VIEW AdminService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM my_bookshop_Authors AS Authors_0; + +CREATE VIEW AdminService_Orders AS SELECT + Orders_0.ID, + Orders_0.createdAt, + Orders_0.createdBy, + Orders_0.modifiedAt, + Orders_0.modifiedBy, + Orders_0.OrderNo, + Orders_0.buyer, + Orders_0.total, + Orders_0.currency_code, + Orders_0.shippingAddress_ID, + Orders_0.shippingAddress_businessPartner +FROM my_bookshop_Orders AS Orders_0; + +CREATE VIEW AdminService_Languages AS SELECT + CommonLanguages_0.name, + CommonLanguages_0.descr, + CommonLanguages_0.code +FROM sap_common_Languages AS CommonLanguages_0; + +CREATE VIEW CatalogService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.modifiedAt, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM my_bookshop_Books AS Books_0; + +CREATE VIEW CatalogService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM my_bookshop_Authors AS Authors_0; + +CREATE VIEW CatalogService_Reviews AS SELECT + Reviews_0.ID, + Reviews_0.createdAt, + Reviews_0.createdBy, + Reviews_0.modifiedAt, + Reviews_0.modifiedBy, + Reviews_0.book_ID, + Reviews_0.rating, + Reviews_0.title, + Reviews_0.text +FROM my_bookshop_Reviews AS Reviews_0; + +CREATE VIEW NotesService_Notes AS SELECT + Notes_0.ID, + Notes_0.note, + Notes_0.address_ID, + Notes_0.address_businessPartner +FROM my_bookshop_Notes AS Notes_0; + +CREATE VIEW ReviewService_Reviews AS SELECT + Reviews_0.ID, + Reviews_0.createdAt, + Reviews_0.createdBy, + Reviews_0.modifiedAt, + Reviews_0.modifiedBy, + Reviews_0.book_ID, + Reviews_0.rating, + Reviews_0.title, + Reviews_0.text +FROM my_bookshop_Reviews AS Reviews_0; + +CREATE VIEW ReviewService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.modifiedAt, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM my_bookshop_Books AS Books_0; + +CREATE VIEW ReviewService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM my_bookshop_Authors AS Authors_0; + +CREATE VIEW AdminService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM my_bookshop_Genres AS Genres_0; + +CREATE VIEW AdminService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM sap_common_Currencies AS Currencies_0; + +CREATE VIEW AdminService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW AdminService_Books_texts AS SELECT + texts_0.ID_texts, + texts_0.locale, + texts_0.ID, + texts_0.title, + texts_0.descr +FROM my_bookshop_Books_texts AS texts_0; + +CREATE VIEW AdminService_OrderItems AS SELECT + OrderItems_0.ID, + OrderItems_0.parent_ID, + OrderItems_0.book_ID, + OrderItems_0.quantity, + OrderItems_0.amount +FROM my_bookshop_OrderItems AS OrderItems_0; + +CREATE VIEW AdminService_Orders_changes AS SELECT + changes_0.up__ID, + changes_0.change_ID +FROM my_bookshop_Orders_changes AS changes_0; + +CREATE VIEW AdminService_Addresses AS SELECT + Addresses_0.ID, + Addresses_0.businessPartner, + Addresses_0.country, + Addresses_0.city, + Addresses_0.postalCode, + Addresses_0.street, + Addresses_0.houseNumber, + Addresses_0.tombstone +FROM my_bookshop_Addresses AS Addresses_0; + +CREATE VIEW AdminService_Languages_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.code +FROM sap_common_Languages_texts AS texts_0; + +CREATE VIEW CatalogService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM my_bookshop_Genres AS Genres_0; + +CREATE VIEW CatalogService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM sap_common_Currencies AS Currencies_0; + +CREATE VIEW CatalogService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW CatalogService_Books_texts AS SELECT + texts_0.ID_texts, + texts_0.locale, + texts_0.ID, + texts_0.title, + texts_0.descr +FROM my_bookshop_Books_texts AS texts_0; + +CREATE VIEW ReviewService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM my_bookshop_Genres AS Genres_0; + +CREATE VIEW ReviewService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM sap_common_Currencies AS Currencies_0; + +CREATE VIEW ReviewService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW ReviewService_Books_texts AS SELECT + texts_0.ID_texts, + texts_0.locale, + texts_0.ID, + texts_0.title, + texts_0.descr +FROM my_bookshop_Books_texts AS texts_0; + +CREATE VIEW AdminService_Genres_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.ID +FROM my_bookshop_Genres_texts AS texts_0; + +CREATE VIEW AdminService_Currencies_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.code +FROM sap_common_Currencies_texts AS texts_0; + +CREATE VIEW AdminService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM Statuses AS Statuses_0; + +CREATE VIEW AdminService_Changes AS SELECT + Changes_0.ID, + Changes_0.createdAt, + Changes_0.createdBy, + Changes_0.changeLogID, + Changes_0.rootEntity, + Changes_0.rootIdentifier, + Changes_0.attribute, + Changes_0.valueChangedFrom, + Changes_0.valueChangedTo, + Changes_0.valueDataType, + Changes_0.targetIdentifier, + Changes_0.targetEntity, + Changes_0.path, + Changes_0.modification +FROM sap_changelog_Changes AS Changes_0; + +CREATE VIEW CatalogService_Genres_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.ID +FROM my_bookshop_Genres_texts AS texts_0; + +CREATE VIEW CatalogService_Currencies_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.code +FROM sap_common_Currencies_texts AS texts_0; + +CREATE VIEW CatalogService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM Statuses AS Statuses_0; + +CREATE VIEW ReviewService_Genres_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.ID +FROM my_bookshop_Genres_texts AS texts_0; + +CREATE VIEW ReviewService_Currencies_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.code +FROM sap_common_Currencies_texts AS texts_0; + +CREATE VIEW ReviewService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM Statuses AS Statuses_0; + +CREATE VIEW AdminService_Statuses_texts AS SELECT + texts_0.locale, + texts_0.code, + texts_0.text +FROM Statuses_texts AS texts_0; + +CREATE VIEW CatalogService_Statuses_texts AS SELECT + texts_0.locale, + texts_0.code, + texts_0.text +FROM Statuses_texts AS texts_0; + +CREATE VIEW ReviewService_Statuses_texts AS SELECT + texts_0.locale, + texts_0.code, + texts_0.text +FROM Statuses_texts AS texts_0; + +CREATE VIEW localized_Statuses AS SELECT + L_0.code, + coalesce(localized_1.text, L_0.text) AS text +FROM (Statuses AS L_0 LEFT JOIN Statuses_texts AS localized_1 ON localized_1.code = L_0.code AND localized_1.locale = @locale); + +CREATE VIEW localized_my_bookshop_Books AS SELECT + L_0.ID, + L_0.createdAt, + L_0.createdBy, + L_0.modifiedAt, + L_0.modifiedBy, + coalesce(localized_1.title, L_0.title) AS title, + coalesce(localized_1.descr, L_0.descr) AS descr, + L_0.author_ID, + L_0.genre_ID, + L_0.stock, + L_0.price, + L_0.currency_code, + L_0.rating, + L_0.isReviewable, + L_0.isbn +FROM (my_bookshop_Books AS L_0 LEFT JOIN my_bookshop_Books_texts AS localized_1 ON localized_1.ID = L_0.ID AND localized_1.locale = @locale); + +CREATE VIEW localized_my_bookshop_Genres AS SELECT + coalesce(localized_1.name, L_0.name) AS name, + coalesce(localized_1.descr, L_0.descr) AS descr, + L_0.ID, + L_0.parent_ID +FROM (my_bookshop_Genres AS L_0 LEFT JOIN my_bookshop_Genres_texts AS localized_1 ON localized_1.ID = L_0.ID AND localized_1.locale = @locale); + +CREATE VIEW localized_sap_common_Languages AS SELECT + coalesce(localized_1.name, L_0.name) AS name, + coalesce(localized_1.descr, L_0.descr) AS descr, + L_0.code +FROM (sap_common_Languages AS L_0 LEFT JOIN sap_common_Languages_texts AS localized_1 ON localized_1.code = L_0.code AND localized_1.locale = @locale); + +CREATE VIEW localized_sap_common_Currencies AS SELECT + coalesce(localized_1.name, L_0.name) AS name, + coalesce(localized_1.descr, L_0.descr) AS descr, + L_0.code, + L_0.symbol, + L_0.minorUnit +FROM (sap_common_Currencies AS L_0 LEFT JOIN sap_common_Currencies_texts AS localized_1 ON localized_1.code = L_0.code AND localized_1.locale = @locale); + +CREATE VIEW localized_my_bookshop_Authors AS SELECT + L.ID, + L.createdAt, + L.createdBy, + L.modifiedAt, + L.modifiedBy, + L.name, + L.dateOfBirth, + L.dateOfDeath, + L.placeOfBirth, + L.placeOfDeath +FROM my_bookshop_Authors AS L; + +CREATE VIEW localized_my_bookshop_Orders AS SELECT + L.ID, + L.createdAt, + L.createdBy, + L.modifiedAt, + L.modifiedBy, + L.OrderNo, + L.buyer, + L.total, + L.currency_code, + L.shippingAddress_ID, + L.shippingAddress_businessPartner +FROM my_bookshop_Orders AS L; + +CREATE VIEW localized_my_bookshop_OrderItems AS SELECT + L.ID, + L.parent_ID, + L.book_ID, + L.quantity, + L.amount +FROM my_bookshop_OrderItems AS L; + +CREATE VIEW localized_my_bookshop_Reviews AS SELECT + L.ID, + L.createdAt, + L.createdBy, + L.modifiedAt, + L.modifiedBy, + L.book_ID, + L.rating, + L.title, + L.text +FROM my_bookshop_Reviews AS L; + +CREATE VIEW localized_my_bookshop_Books_attachments AS SELECT + L.up__ID, + L.ID, + L.createdAt, + L.createdBy, + L.modifiedAt, + L.modifiedBy, + L.content, + L.mimeType, + L.fileName, + L.contentId, + L.status, + L.scannedAt, + L.note, + L.folderId, + L.repositoryId, + L.objectId +FROM my_bookshop_Books_attachments AS L; + +CREATE VIEW localized_my_bookshop_Orders_changes AS SELECT + L.up__ID, + L.change_ID +FROM my_bookshop_Orders_changes AS L; + +CREATE VIEW AdminService_DraftAdministrativeData AS SELECT + DraftAdministrativeData.DraftUUID, + DraftAdministrativeData.CreationDateTime, + DraftAdministrativeData.CreatedByUser, + DraftAdministrativeData.DraftIsCreatedByMe, + DraftAdministrativeData.LastChangeDateTime, + DraftAdministrativeData.LastChangedByUser, + DraftAdministrativeData.InProcessByUser, + DraftAdministrativeData.DraftIsProcessedByMe +FROM DRAFT_DraftAdministrativeData AS DraftAdministrativeData; + +CREATE VIEW NotesService_DraftAdministrativeData AS SELECT + DraftAdministrativeData.DraftUUID, + DraftAdministrativeData.CreationDateTime, + DraftAdministrativeData.CreatedByUser, + DraftAdministrativeData.DraftIsCreatedByMe, + DraftAdministrativeData.LastChangeDateTime, + DraftAdministrativeData.LastChangedByUser, + DraftAdministrativeData.InProcessByUser, + DraftAdministrativeData.DraftIsProcessedByMe +FROM DRAFT_DraftAdministrativeData AS DraftAdministrativeData; + +CREATE VIEW ReviewService_DraftAdministrativeData AS SELECT + DraftAdministrativeData.DraftUUID, + DraftAdministrativeData.CreationDateTime, + DraftAdministrativeData.CreatedByUser, + DraftAdministrativeData.DraftIsCreatedByMe, + DraftAdministrativeData.LastChangeDateTime, + DraftAdministrativeData.LastChangedByUser, + DraftAdministrativeData.InProcessByUser, + DraftAdministrativeData.DraftIsProcessedByMe +FROM DRAFT_DraftAdministrativeData AS DraftAdministrativeData; + +CREATE VIEW localized_AdminService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.createdBy, + Books_0.modifiedAt, + Books_0.modifiedBy, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM localized_my_bookshop_Books AS Books_0; + +CREATE VIEW localized_AdminService_Languages AS SELECT + CommonLanguages_0.name, + CommonLanguages_0.descr, + CommonLanguages_0.code +FROM localized_sap_common_Languages AS CommonLanguages_0; + +CREATE VIEW localized_CatalogService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.modifiedAt, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM localized_my_bookshop_Books AS Books_0; + +CREATE VIEW localized_ReviewService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.modifiedAt, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM localized_my_bookshop_Books AS Books_0; + +CREATE VIEW localized_AdminService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM localized_my_bookshop_Genres AS Genres_0; + +CREATE VIEW localized_AdminService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM localized_sap_common_Currencies AS Currencies_0; + +CREATE VIEW localized_CatalogService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM localized_my_bookshop_Genres AS Genres_0; + +CREATE VIEW localized_CatalogService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM localized_sap_common_Currencies AS Currencies_0; + +CREATE VIEW localized_ReviewService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM localized_my_bookshop_Genres AS Genres_0; + +CREATE VIEW localized_ReviewService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM localized_sap_common_Currencies AS Currencies_0; + +CREATE VIEW localized_AdminService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM localized_Statuses AS Statuses_0; + +CREATE VIEW localized_CatalogService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM localized_Statuses AS Statuses_0; + +CREATE VIEW localized_ReviewService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM localized_Statuses AS Statuses_0; + +CREATE VIEW localized_AdminService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM localized_my_bookshop_Authors AS Authors_0; + +CREATE VIEW localized_AdminService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM localized_my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW localized_AdminService_OrderItems AS SELECT + OrderItems_0.ID, + OrderItems_0.parent_ID, + OrderItems_0.book_ID, + OrderItems_0.quantity, + OrderItems_0.amount +FROM localized_my_bookshop_OrderItems AS OrderItems_0; + +CREATE VIEW localized_CatalogService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM localized_my_bookshop_Authors AS Authors_0; + +CREATE VIEW localized_CatalogService_Reviews AS SELECT + Reviews_0.ID, + Reviews_0.createdAt, + Reviews_0.createdBy, + Reviews_0.modifiedAt, + Reviews_0.modifiedBy, + Reviews_0.book_ID, + Reviews_0.rating, + Reviews_0.title, + Reviews_0.text +FROM localized_my_bookshop_Reviews AS Reviews_0; + +CREATE VIEW localized_CatalogService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM localized_my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW localized_ReviewService_Reviews AS SELECT + Reviews_0.ID, + Reviews_0.createdAt, + Reviews_0.createdBy, + Reviews_0.modifiedAt, + Reviews_0.modifiedBy, + Reviews_0.book_ID, + Reviews_0.rating, + Reviews_0.title, + Reviews_0.text +FROM localized_my_bookshop_Reviews AS Reviews_0; + +CREATE VIEW localized_ReviewService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM localized_my_bookshop_Authors AS Authors_0; + +CREATE VIEW localized_ReviewService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM localized_my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW localized_AdminService_Orders AS SELECT + Orders_0.ID, + Orders_0.createdAt, + Orders_0.createdBy, + Orders_0.modifiedAt, + Orders_0.modifiedBy, + Orders_0.OrderNo, + Orders_0.buyer, + Orders_0.total, + Orders_0.currency_code, + Orders_0.shippingAddress_ID, + Orders_0.shippingAddress_businessPartner +FROM localized_my_bookshop_Orders AS Orders_0; + +CREATE VIEW localized_AdminService_Orders_changes AS SELECT + changes_0.up__ID, + changes_0.change_ID +FROM localized_my_bookshop_Orders_changes AS changes_0; + diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/schema.sql b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/schema.sql new file mode 100644 index 000000000..08469b10c --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/schema.sql @@ -0,0 +1,1963 @@ + +DROP VIEW IF EXISTS localized_AdminService_Orders_changes; +DROP VIEW IF EXISTS localized_AdminService_Orders; +DROP VIEW IF EXISTS localized_ReviewService_Books_attachments; +DROP VIEW IF EXISTS localized_ReviewService_Authors; +DROP VIEW IF EXISTS localized_ReviewService_Reviews; +DROP VIEW IF EXISTS localized_CatalogService_Books_attachments; +DROP VIEW IF EXISTS localized_CatalogService_Reviews; +DROP VIEW IF EXISTS localized_CatalogService_Authors; +DROP VIEW IF EXISTS localized_AdminService_OrderItems; +DROP VIEW IF EXISTS localized_AdminService_Books_attachments; +DROP VIEW IF EXISTS localized_AdminService_Authors; +DROP VIEW IF EXISTS localized_ReviewService_Statuses; +DROP VIEW IF EXISTS localized_CatalogService_Statuses; +DROP VIEW IF EXISTS localized_AdminService_Statuses; +DROP VIEW IF EXISTS localized_ReviewService_Currencies; +DROP VIEW IF EXISTS localized_ReviewService_Genres; +DROP VIEW IF EXISTS localized_CatalogService_Currencies; +DROP VIEW IF EXISTS localized_CatalogService_Genres; +DROP VIEW IF EXISTS localized_AdminService_Currencies; +DROP VIEW IF EXISTS localized_AdminService_Genres; +DROP VIEW IF EXISTS localized_ReviewService_Books; +DROP VIEW IF EXISTS localized_CatalogService_Books; +DROP VIEW IF EXISTS localized_AdminService_Languages; +DROP VIEW IF EXISTS localized_AdminService_Books; +DROP VIEW IF EXISTS NotesService_Addresses; +DROP VIEW IF EXISTS ReviewService_DraftAdministrativeData; +DROP VIEW IF EXISTS NotesService_DraftAdministrativeData; +DROP VIEW IF EXISTS AdminService_DraftAdministrativeData; +DROP VIEW IF EXISTS localized_my_bookshop_Orders_changes; +DROP VIEW IF EXISTS localized_my_bookshop_Books_attachments; +DROP VIEW IF EXISTS localized_my_bookshop_Reviews; +DROP VIEW IF EXISTS localized_my_bookshop_OrderItems; +DROP VIEW IF EXISTS localized_my_bookshop_Orders; +DROP VIEW IF EXISTS localized_my_bookshop_Authors; +DROP VIEW IF EXISTS localized_sap_common_Currencies; +DROP VIEW IF EXISTS localized_sap_common_Languages; +DROP VIEW IF EXISTS localized_my_bookshop_Genres; +DROP VIEW IF EXISTS localized_my_bookshop_Books; +DROP VIEW IF EXISTS localized_Statuses; +DROP VIEW IF EXISTS ReviewService_Statuses_texts; +DROP VIEW IF EXISTS CatalogService_Statuses_texts; +DROP VIEW IF EXISTS AdminService_Statuses_texts; +DROP VIEW IF EXISTS ReviewService_Statuses; +DROP VIEW IF EXISTS ReviewService_Currencies_texts; +DROP VIEW IF EXISTS ReviewService_Genres_texts; +DROP VIEW IF EXISTS CatalogService_Statuses; +DROP VIEW IF EXISTS CatalogService_Currencies_texts; +DROP VIEW IF EXISTS CatalogService_Genres_texts; +DROP VIEW IF EXISTS AdminService_Changes; +DROP VIEW IF EXISTS AdminService_Statuses; +DROP VIEW IF EXISTS AdminService_Currencies_texts; +DROP VIEW IF EXISTS AdminService_Genres_texts; +DROP VIEW IF EXISTS ReviewService_Books_texts; +DROP VIEW IF EXISTS ReviewService_Books_attachments; +DROP VIEW IF EXISTS ReviewService_Currencies; +DROP VIEW IF EXISTS ReviewService_Genres; +DROP VIEW IF EXISTS CatalogService_Books_texts; +DROP VIEW IF EXISTS CatalogService_Books_attachments; +DROP VIEW IF EXISTS CatalogService_Currencies; +DROP VIEW IF EXISTS CatalogService_Genres; +DROP VIEW IF EXISTS AdminService_Languages_texts; +DROP VIEW IF EXISTS AdminService_Addresses; +DROP VIEW IF EXISTS AdminService_Orders_changes; +DROP VIEW IF EXISTS AdminService_OrderItems; +DROP VIEW IF EXISTS AdminService_Books_texts; +DROP VIEW IF EXISTS AdminService_Books_attachments; +DROP VIEW IF EXISTS AdminService_Currencies; +DROP VIEW IF EXISTS AdminService_Genres; +DROP VIEW IF EXISTS ReviewService_Authors; +DROP VIEW IF EXISTS ReviewService_Books; +DROP VIEW IF EXISTS ReviewService_Reviews; +DROP VIEW IF EXISTS NotesService_Notes; +DROP VIEW IF EXISTS my_bookshop_NoteableAddresses; +DROP VIEW IF EXISTS CatalogService_Reviews; +DROP VIEW IF EXISTS CatalogService_Authors; +DROP VIEW IF EXISTS CatalogService_Books; +DROP VIEW IF EXISTS AdminService_Languages; +DROP VIEW IF EXISTS AdminService_Orders; +DROP VIEW IF EXISTS AdminService_Authors; +DROP VIEW IF EXISTS AdminService_Books; +DROP TABLE IF EXISTS ReviewService_Reviews_drafts; +DROP TABLE IF EXISTS NotesService_Notes_drafts; +DROP TABLE IF EXISTS AdminService_OrderItems_drafts; +DROP TABLE IF EXISTS AdminService_Orders_drafts; +DROP TABLE IF EXISTS AdminService_Books_texts_drafts; +DROP TABLE IF EXISTS AdminService_Books_attachments_drafts; +DROP TABLE IF EXISTS AdminService_Books_drafts; +DROP TABLE IF EXISTS DRAFT_DraftAdministrativeData; +DROP TABLE IF EXISTS sap_common_Currencies_texts; +DROP TABLE IF EXISTS sap_common_Languages_texts; +DROP TABLE IF EXISTS my_bookshop_Orders_changes; +DROP TABLE IF EXISTS my_bookshop_Genres_texts; +DROP TABLE IF EXISTS my_bookshop_Books_texts; +DROP TABLE IF EXISTS my_bookshop_Books_attachments; +DROP TABLE IF EXISTS Statuses_texts; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_SupplierWithHoldingTax; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_SupplierPurchasingOrg; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_SupplierPartnerFunc; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_SupplierDunning; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_SupplierCompany; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_Supplier; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_CustSalesPartnerFunc; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_CustomerWithHoldingTax; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_CustomerSalesAreaTax; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_CustomerSalesArea; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_CustomerDunning; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_CustomerCompany; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_Customer; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BusinessPartnerTaxNumber; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BusinessPartnerRole; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BusinessPartnerContact; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BusinessPartnerBank; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BusinessPartnerAddress; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BusinessPartner; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BuPaIndustry; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BuPaIdentification; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BuPaAddressUsage; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BPContactToFuncAndDept; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_BPContactToAddress; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_AddressPhoneNumber; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_AddressHomePageURL; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_AddressFaxNumber; +DROP TABLE IF EXISTS API_BUSINESS_PARTNER_A_AddressEmailAddress; +DROP TABLE IF EXISTS sap_changelog_Changes; +DROP TABLE IF EXISTS sap_common_Currencies; +DROP TABLE IF EXISTS sap_common_Languages; +DROP TABLE IF EXISTS cds_outbox_Messages; +DROP TABLE IF EXISTS my_bookshop_Notes; +DROP TABLE IF EXISTS my_bookshop_Reviews; +DROP TABLE IF EXISTS my_bookshop_OrderItems; +DROP TABLE IF EXISTS my_bookshop_Orders; +DROP TABLE IF EXISTS my_bookshop_Genres; +DROP TABLE IF EXISTS my_bookshop_Authors; +DROP TABLE IF EXISTS my_bookshop_Books; +DROP TABLE IF EXISTS cds_xt_Extensions; +DROP TABLE IF EXISTS my_bookshop_Addresses; +DROP TABLE IF EXISTS Statuses; +DROP TABLE IF EXISTS AdminService_Upload; + +CREATE TABLE AdminService_Upload ( + csv BINARY LARGE OBJECT +); + +CREATE TABLE Statuses ( + code NVARCHAR(255) NOT NULL, + text NVARCHAR(255), + PRIMARY KEY(code) +); + +CREATE TABLE my_bookshop_Addresses ( + ID NVARCHAR(10) NOT NULL, + businessPartner NVARCHAR(10) NOT NULL, + country NVARCHAR(3), + city NVARCHAR(40), + postalCode NVARCHAR(10), + street NVARCHAR(60), + houseNumber NVARCHAR(10), + tombstone BOOLEAN, + PRIMARY KEY(ID, businessPartner) +); + +CREATE TABLE cds_xt_Extensions ( + ID NVARCHAR(36) NOT NULL, + tag NVARCHAR(255), + csn NCLOB, + i18n NCLOB, + sources BINARY LARGE OBJECT, + activated NVARCHAR(255), + timestamp TIMESTAMP(7), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Books ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + modifiedAt TIMESTAMP(7), + modifiedBy NVARCHAR(255), + title NVARCHAR(111), + descr NVARCHAR(1111), + author_ID NVARCHAR(36), + genre_ID INTEGER, + stock INTEGER, + price DECIMAL(9, 2), + currency_code NVARCHAR(3), + rating DECIMAL(2, 1), + isReviewable BOOLEAN NOT NULL DEFAULT TRUE, + isbn NVARCHAR(40), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Authors ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + modifiedAt TIMESTAMP(7), + modifiedBy NVARCHAR(255), + name NVARCHAR(111), + dateOfBirth DATE, + dateOfDeath DATE, + placeOfBirth NVARCHAR(255), + placeOfDeath NVARCHAR(255), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Genres ( + name NVARCHAR(255), + descr NVARCHAR(1000), + ID INTEGER NOT NULL, + parent_ID INTEGER, + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Orders ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + modifiedAt TIMESTAMP(7), + modifiedBy NVARCHAR(255), + OrderNo NVARCHAR(255), + buyer NVARCHAR(255), + total DECIMAL(9, 2), + currency_code NVARCHAR(3), + shippingAddress_ID NVARCHAR(10), + shippingAddress_businessPartner NVARCHAR(10), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_OrderItems ( + ID NVARCHAR(36) NOT NULL, + parent_ID NVARCHAR(36), + book_ID NVARCHAR(36), + quantity INTEGER, + amount DECIMAL(9, 2), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Reviews ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + modifiedAt TIMESTAMP(7), + modifiedBy NVARCHAR(255), + book_ID NVARCHAR(36), + rating INTEGER, + title NVARCHAR(111), + text NVARCHAR(1111), + PRIMARY KEY(ID) +); + +CREATE TABLE my_bookshop_Notes ( + ID NVARCHAR(36) NOT NULL, + note NVARCHAR(255), + address_ID NVARCHAR(10), + address_businessPartner NVARCHAR(10), + PRIMARY KEY(ID) +); + +CREATE TABLE cds_outbox_Messages ( + ID NVARCHAR(36) NOT NULL, + timestamp TIMESTAMP(7), + target NVARCHAR(255), + msg NCLOB, + attempts INTEGER DEFAULT 0, + "PARTITION" INTEGER DEFAULT 0, + lastError NCLOB, + lastAttemptTimestamp TIMESTAMP(7), + PRIMARY KEY(ID) +); + +CREATE TABLE sap_common_Languages ( + name NVARCHAR(255), + descr NVARCHAR(1000), + code NVARCHAR(14) NOT NULL, + PRIMARY KEY(code) +); + +CREATE TABLE sap_common_Currencies ( + name NVARCHAR(255), + descr NVARCHAR(1000), + code NVARCHAR(3) NOT NULL, + symbol NVARCHAR(5), + minorUnit SMALLINT, + PRIMARY KEY(code) +); + +CREATE TABLE sap_changelog_Changes ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + changeLogID NVARCHAR(36), + rootEntity NVARCHAR(255), + rootIdentifier NVARCHAR(255), + attribute NVARCHAR(255), + valueChangedFrom NVARCHAR(5000), + valueChangedTo NVARCHAR(5000), + valueDataType NVARCHAR(255), + targetIdentifier NVARCHAR(255), + targetEntity NVARCHAR(255), + path NVARCHAR(5000), + modification NVARCHAR(255), + PRIMARY KEY(ID) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_AddressEmailAddress ( + AddressID NVARCHAR(10) NOT NULL, + Person NVARCHAR(10) NOT NULL, + OrdinalNumber NVARCHAR(3) NOT NULL, + IsDefaultEmailAddress BOOLEAN, + EmailAddress NVARCHAR(241), + SearchEmailAddress NVARCHAR(20), + AddressCommunicationRemarkText NVARCHAR(50), + PRIMARY KEY(AddressID, Person, OrdinalNumber) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_AddressFaxNumber ( + AddressID NVARCHAR(10) NOT NULL, + Person NVARCHAR(10) NOT NULL, + OrdinalNumber NVARCHAR(3) NOT NULL, + IsDefaultFaxNumber BOOLEAN, + FaxCountry NVARCHAR(3), + FaxNumber NVARCHAR(30), + FaxNumberExtension NVARCHAR(10), + InternationalFaxNumber NVARCHAR(30), + AddressCommunicationRemarkText NVARCHAR(50), + PRIMARY KEY(AddressID, Person, OrdinalNumber) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_AddressHomePageURL ( + AddressID NVARCHAR(10) NOT NULL, + Person NVARCHAR(10) NOT NULL, + OrdinalNumber NVARCHAR(3) NOT NULL, + ValidityStartDate DATE NOT NULL, + IsDefaultURLAddress BOOLEAN NOT NULL, + SearchURLAddress NVARCHAR(50), + AddressCommunicationRemarkText NVARCHAR(50), + URLFieldLength INTEGER, + WebsiteURL NVARCHAR(2048), + PRIMARY KEY(AddressID, Person, OrdinalNumber, ValidityStartDate, IsDefaultURLAddress) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_AddressPhoneNumber ( + AddressID NVARCHAR(10) NOT NULL, + Person NVARCHAR(10) NOT NULL, + OrdinalNumber NVARCHAR(3) NOT NULL, + DestinationLocationCountry NVARCHAR(3), + IsDefaultPhoneNumber BOOLEAN, + PhoneNumber NVARCHAR(30), + PhoneNumberExtension NVARCHAR(10), + InternationalPhoneNumber NVARCHAR(30), + PhoneNumberType NVARCHAR(1), + AddressCommunicationRemarkText NVARCHAR(50), + PRIMARY KEY(AddressID, Person, OrdinalNumber) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BPContactToAddress ( + RelationshipNumber NVARCHAR(12) NOT NULL, + BusinessPartnerCompany NVARCHAR(10) NOT NULL, + BusinessPartnerPerson NVARCHAR(10) NOT NULL, + ValidityEndDate DATE NOT NULL, + AddressID NVARCHAR(10) NOT NULL, + AddressNumber NVARCHAR(10), + AdditionalStreetPrefixName NVARCHAR(40), + AdditionalStreetSuffixName NVARCHAR(40), + AddressTimeZone NVARCHAR(6), + CareOfName NVARCHAR(40), + CityCode NVARCHAR(12), + CityName NVARCHAR(40), + CompanyPostalCode NVARCHAR(10), + Country NVARCHAR(3), + County NVARCHAR(40), + DeliveryServiceNumber NVARCHAR(10), + DeliveryServiceTypeCode NVARCHAR(4), + District NVARCHAR(40), + FormOfAddress NVARCHAR(4), + FullName NVARCHAR(80), + HomeCityName NVARCHAR(40), + HouseNumber NVARCHAR(10), + HouseNumberSupplementText NVARCHAR(10), + Language NVARCHAR(2), + POBox NVARCHAR(10), + POBoxDeviatingCityName NVARCHAR(40), + POBoxDeviatingCountry NVARCHAR(3), + POBoxDeviatingRegion NVARCHAR(3), + POBoxIsWithoutNumber BOOLEAN, + POBoxLobbyName NVARCHAR(40), + POBoxPostalCode NVARCHAR(10), + Person NVARCHAR(10), + PostalCode NVARCHAR(10), + PrfrdCommMediumType NVARCHAR(3), + Region NVARCHAR(3), + StreetName NVARCHAR(60), + StreetPrefixName NVARCHAR(40), + StreetSuffixName NVARCHAR(40), + TaxJurisdiction NVARCHAR(15), + TransportZone NVARCHAR(10), + PRIMARY KEY(RelationshipNumber, BusinessPartnerCompany, BusinessPartnerPerson, ValidityEndDate, AddressID) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BPContactToFuncAndDept ( + RelationshipNumber NVARCHAR(12) NOT NULL, + BusinessPartnerCompany NVARCHAR(10) NOT NULL, + BusinessPartnerPerson NVARCHAR(10) NOT NULL, + ValidityEndDate DATE NOT NULL, + ContactPersonFunction NVARCHAR(4), + ContactPersonDepartment NVARCHAR(4), + PhoneNumber NVARCHAR(30), + PhoneNumberExtension NVARCHAR(10), + FaxNumber NVARCHAR(30), + FaxNumberExtension NVARCHAR(10), + EmailAddress NVARCHAR(241), + RelationshipCategory NVARCHAR(6), + PRIMARY KEY(RelationshipNumber, BusinessPartnerCompany, BusinessPartnerPerson, ValidityEndDate) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BuPaAddressUsage ( + BusinessPartner NVARCHAR(10) NOT NULL, + ValidityEndDate TIMESTAMP(0) NOT NULL, + AddressUsage NVARCHAR(10) NOT NULL, + AddressID NVARCHAR(10) NOT NULL, + ValidityStartDate TIMESTAMP(0), + StandardUsage BOOLEAN, + AuthorizationGroup NVARCHAR(4), + PRIMARY KEY(BusinessPartner, ValidityEndDate, AddressUsage, AddressID) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BuPaIdentification ( + BusinessPartner NVARCHAR(10) NOT NULL, + BPIdentificationType NVARCHAR(6) NOT NULL, + BPIdentificationNumber NVARCHAR(60) NOT NULL, + BPIdnNmbrIssuingInstitute NVARCHAR(40), + BPIdentificationEntryDate DATE, + Country NVARCHAR(3), + Region NVARCHAR(3), + ValidityStartDate DATE, + ValidityEndDate DATE, + AuthorizationGroup NVARCHAR(4), + PRIMARY KEY(BusinessPartner, BPIdentificationType, BPIdentificationNumber) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BuPaIndustry ( + IndustrySector NVARCHAR(10) NOT NULL, + IndustrySystemType NVARCHAR(4) NOT NULL, + BusinessPartner NVARCHAR(10) NOT NULL, + IsStandardIndustry NVARCHAR(1), + IndustryKeyDescription NVARCHAR(100), + PRIMARY KEY(IndustrySector, IndustrySystemType, BusinessPartner) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BusinessPartner ( + BusinessPartner NVARCHAR(10) NOT NULL, + Customer NVARCHAR(10), + Supplier NVARCHAR(10), + AcademicTitle NVARCHAR(4), + AuthorizationGroup NVARCHAR(4), + BusinessPartnerCategory NVARCHAR(1), + BusinessPartnerFullName NVARCHAR(81), + BusinessPartnerGrouping NVARCHAR(4), + BusinessPartnerName NVARCHAR(81), + BusinessPartnerUUID NVARCHAR(36), + CorrespondenceLanguage NVARCHAR(2), + CreatedByUser NVARCHAR(12), + CreationDate DATE, + CreationTime TIME, + FirstName NVARCHAR(40), + FormOfAddress NVARCHAR(4), + Industry NVARCHAR(10), + InternationalLocationNumber1 NVARCHAR(7), + InternationalLocationNumber2 NVARCHAR(5), + IsFemale BOOLEAN, + IsMale BOOLEAN, + IsNaturalPerson NVARCHAR(1), + IsSexUnknown BOOLEAN, + GenderCodeName NVARCHAR(1), + Language NVARCHAR(2), + LastChangeDate DATE, + LastChangeTime TIME, + LastChangedByUser NVARCHAR(12), + LastName NVARCHAR(40), + LegalForm NVARCHAR(2), + OrganizationBPName1 NVARCHAR(40), + OrganizationBPName2 NVARCHAR(40), + OrganizationBPName3 NVARCHAR(40), + OrganizationBPName4 NVARCHAR(40), + OrganizationFoundationDate DATE, + OrganizationLiquidationDate DATE, + SearchTerm1 NVARCHAR(20), + SearchTerm2 NVARCHAR(20), + AdditionalLastName NVARCHAR(40), + BirthDate DATE, + BusinessPartnerBirthplaceName NVARCHAR(40), + BusinessPartnerIsBlocked BOOLEAN, + BusinessPartnerType NVARCHAR(4), + ETag NVARCHAR(26), + GroupBusinessPartnerName1 NVARCHAR(40), + GroupBusinessPartnerName2 NVARCHAR(40), + IndependentAddressID NVARCHAR(10), + InternationalLocationNumber3 NVARCHAR(1), + MiddleName NVARCHAR(40), + NameCountry NVARCHAR(3), + NameFormat NVARCHAR(2), + PersonFullName NVARCHAR(80), + PersonNumber NVARCHAR(10), + IsMarkedForArchiving BOOLEAN, + BusinessPartnerIDByExtSystem NVARCHAR(20), + TradingPartner NVARCHAR(6), + PRIMARY KEY(BusinessPartner) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BusinessPartnerAddress ( + BusinessPartner NVARCHAR(10) NOT NULL, + AddressID NVARCHAR(10) NOT NULL, + ValidityStartDate TIMESTAMP(0), + ValidityEndDate TIMESTAMP(0), + AuthorizationGroup NVARCHAR(4), + AddressUUID NVARCHAR(36), + AdditionalStreetPrefixName NVARCHAR(40), + AdditionalStreetSuffixName NVARCHAR(40), + AddressTimeZone NVARCHAR(6), + CareOfName NVARCHAR(40), + CityCode NVARCHAR(12), + CityName NVARCHAR(40), + CompanyPostalCode NVARCHAR(10), + Country NVARCHAR(3), + County NVARCHAR(40), + DeliveryServiceNumber NVARCHAR(10), + DeliveryServiceTypeCode NVARCHAR(4), + District NVARCHAR(40), + FormOfAddress NVARCHAR(4), + FullName NVARCHAR(80), + HomeCityName NVARCHAR(40), + HouseNumber NVARCHAR(10), + HouseNumberSupplementText NVARCHAR(10), + Language NVARCHAR(2), + POBox NVARCHAR(10), + POBoxDeviatingCityName NVARCHAR(40), + POBoxDeviatingCountry NVARCHAR(3), + POBoxDeviatingRegion NVARCHAR(3), + POBoxIsWithoutNumber BOOLEAN, + POBoxLobbyName NVARCHAR(40), + POBoxPostalCode NVARCHAR(10), + Person NVARCHAR(10), + PostalCode NVARCHAR(10), + PrfrdCommMediumType NVARCHAR(3), + Region NVARCHAR(3), + StreetName NVARCHAR(60), + StreetPrefixName NVARCHAR(40), + StreetSuffixName NVARCHAR(40), + TaxJurisdiction NVARCHAR(15), + TransportZone NVARCHAR(10), + AddressIDByExternalSystem NVARCHAR(20), + PRIMARY KEY(BusinessPartner, AddressID) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BusinessPartnerBank ( + BusinessPartner NVARCHAR(10) NOT NULL, + BankIdentification NVARCHAR(4) NOT NULL, + BankCountryKey NVARCHAR(3), + BankName NVARCHAR(60), + BankNumber NVARCHAR(15), + SWIFTCode NVARCHAR(11), + BankControlKey NVARCHAR(2), + BankAccountHolderName NVARCHAR(60), + BankAccountName NVARCHAR(40), + ValidityStartDate TIMESTAMP(0), + ValidityEndDate TIMESTAMP(0), + IBAN NVARCHAR(34), + IBANValidityStartDate DATE, + BankAccount NVARCHAR(18), + BankAccountReferenceText NVARCHAR(20), + CollectionAuthInd BOOLEAN, + CityName NVARCHAR(35), + AuthorizationGroup NVARCHAR(4), + PRIMARY KEY(BusinessPartner, BankIdentification) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BusinessPartnerContact ( + RelationshipNumber NVARCHAR(12) NOT NULL, + BusinessPartnerCompany NVARCHAR(10) NOT NULL, + BusinessPartnerPerson NVARCHAR(10) NOT NULL, + ValidityEndDate DATE NOT NULL, + ValidityStartDate DATE, + IsStandardRelationship BOOLEAN, + RelationshipCategory NVARCHAR(6), + PRIMARY KEY(RelationshipNumber, BusinessPartnerCompany, BusinessPartnerPerson, ValidityEndDate) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BusinessPartnerRole ( + BusinessPartner NVARCHAR(10) NOT NULL, + BusinessPartnerRole NVARCHAR(6) NOT NULL, + ValidFrom TIMESTAMP(0), + ValidTo TIMESTAMP(0), + AuthorizationGroup NVARCHAR(4), + PRIMARY KEY(BusinessPartner, BusinessPartnerRole) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_BusinessPartnerTaxNumber ( + BusinessPartner NVARCHAR(10) NOT NULL, + BPTaxType NVARCHAR(4) NOT NULL, + BPTaxNumber NVARCHAR(20), + BPTaxLongNumber NVARCHAR(60), + AuthorizationGroup NVARCHAR(4), + PRIMARY KEY(BusinessPartner, BPTaxType) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_Customer ( + Customer NVARCHAR(10) NOT NULL, + AuthorizationGroup NVARCHAR(4), + BillingIsBlockedForCustomer NVARCHAR(2), + CreatedByUser NVARCHAR(12), + CreationDate DATE, + CustomerAccountGroup NVARCHAR(4), + CustomerClassification NVARCHAR(2), + CustomerFullName NVARCHAR(220), + CustomerName NVARCHAR(80), + DeliveryIsBlocked NVARCHAR(2), + NFPartnerIsNaturalPerson NVARCHAR(1), + OrderIsBlockedForCustomer NVARCHAR(2), + PostingIsBlocked BOOLEAN, + Supplier NVARCHAR(10), + CustomerCorporateGroup NVARCHAR(10), + FiscalAddress NVARCHAR(10), + Industry NVARCHAR(4), + IndustryCode1 NVARCHAR(10), + IndustryCode2 NVARCHAR(10), + IndustryCode3 NVARCHAR(10), + IndustryCode4 NVARCHAR(10), + IndustryCode5 NVARCHAR(10), + InternationalLocationNumber1 NVARCHAR(7), + NielsenRegion NVARCHAR(2), + ResponsibleType NVARCHAR(2), + TaxNumber1 NVARCHAR(16), + TaxNumber2 NVARCHAR(11), + TaxNumber3 NVARCHAR(18), + TaxNumber4 NVARCHAR(18), + TaxNumber5 NVARCHAR(60), + TaxNumberType NVARCHAR(2), + VATRegistration NVARCHAR(20), + DeletionIndicator BOOLEAN, + PRIMARY KEY(Customer) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_CustomerCompany ( + Customer NVARCHAR(10) NOT NULL, + CompanyCode NVARCHAR(4) NOT NULL, + APARToleranceGroup NVARCHAR(4), + AccountByCustomer NVARCHAR(12), + AccountingClerk NVARCHAR(2), + AccountingClerkFaxNumber NVARCHAR(31), + AccountingClerkInternetAddress NVARCHAR(130), + AccountingClerkPhoneNumber NVARCHAR(30), + AlternativePayerAccount NVARCHAR(10), + AuthorizationGroup NVARCHAR(4), + CollectiveInvoiceVariant NVARCHAR(1), + CustomerAccountNote NVARCHAR(30), + CustomerHeadOffice NVARCHAR(10), + CustomerSupplierClearingIsUsed BOOLEAN, + HouseBank NVARCHAR(5), + InterestCalculationCode NVARCHAR(2), + InterestCalculationDate DATE, + IsToBeLocallyProcessed BOOLEAN, + ItemIsToBePaidSeparately BOOLEAN, + LayoutSortingRule NVARCHAR(3), + PaymentBlockingReason NVARCHAR(1), + PaymentMethodsList NVARCHAR(10), + PaymentTerms NVARCHAR(4), + PaytAdviceIsSentbyEDI BOOLEAN, + PhysicalInventoryBlockInd BOOLEAN, + ReconciliationAccount NVARCHAR(10), + RecordPaymentHistoryIndicator BOOLEAN, + UserAtCustomer NVARCHAR(15), + DeletionIndicator BOOLEAN, + CashPlanningGroup NVARCHAR(10), + KnownOrNegotiatedLeave NVARCHAR(4), + ValueAdjustmentKey NVARCHAR(2), + CustomerAccountGroup NVARCHAR(4), + PRIMARY KEY(Customer, CompanyCode) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_CustomerDunning ( + Customer NVARCHAR(10) NOT NULL, + CompanyCode NVARCHAR(4) NOT NULL, + DunningArea NVARCHAR(2) NOT NULL, + DunningBlock NVARCHAR(1), + DunningLevel NVARCHAR(1), + DunningProcedure NVARCHAR(4), + DunningRecipient NVARCHAR(10), + LastDunnedOn DATE, + LegDunningProcedureOn DATE, + DunningClerk NVARCHAR(2), + AuthorizationGroup NVARCHAR(4), + CustomerAccountGroup NVARCHAR(4), + PRIMARY KEY(Customer, CompanyCode, DunningArea) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_CustomerSalesArea ( + Customer NVARCHAR(10) NOT NULL, + SalesOrganization NVARCHAR(4) NOT NULL, + DistributionChannel NVARCHAR(2) NOT NULL, + Division NVARCHAR(2) NOT NULL, + AccountByCustomer NVARCHAR(12), + AuthorizationGroup NVARCHAR(4), + BillingIsBlockedForCustomer NVARCHAR(2), + CompleteDeliveryIsDefined BOOLEAN, + Currency NVARCHAR(5), + CustomerABCClassification NVARCHAR(2), + CustomerAccountAssignmentGroup NVARCHAR(2), + CustomerGroup NVARCHAR(2), + CustomerPaymentTerms NVARCHAR(4), + CustomerPriceGroup NVARCHAR(2), + CustomerPricingProcedure NVARCHAR(2), + DeliveryIsBlockedForCustomer NVARCHAR(2), + DeliveryPriority NVARCHAR(2), + IncotermsClassification NVARCHAR(3), + IncotermsLocation2 NVARCHAR(70), + IncotermsVersion NVARCHAR(4), + IncotermsLocation1 NVARCHAR(70), + DeletionIndicator BOOLEAN, + IncotermsTransferLocation NVARCHAR(28), + InvoiceDate NVARCHAR(2), + ItemOrderProbabilityInPercent NVARCHAR(3), + OrderCombinationIsAllowed BOOLEAN, + OrderIsBlockedForCustomer NVARCHAR(2), + PartialDeliveryIsAllowed NVARCHAR(1), + PriceListType NVARCHAR(2), + SalesGroup NVARCHAR(3), + SalesOffice NVARCHAR(4), + ShippingCondition NVARCHAR(2), + SupplyingPlant NVARCHAR(4), + SalesDistrict NVARCHAR(6), + InvoiceListSchedule NVARCHAR(2), + ExchangeRateType NVARCHAR(4), + AdditionalCustomerGroup1 NVARCHAR(3), + AdditionalCustomerGroup2 NVARCHAR(3), + AdditionalCustomerGroup3 NVARCHAR(3), + AdditionalCustomerGroup4 NVARCHAR(3), + AdditionalCustomerGroup5 NVARCHAR(3), + PaymentGuaranteeProcedure NVARCHAR(4), + CustomerAccountGroup NVARCHAR(4), + PRIMARY KEY(Customer, SalesOrganization, DistributionChannel, Division) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_CustomerSalesAreaTax ( + Customer NVARCHAR(10) NOT NULL, + SalesOrganization NVARCHAR(4) NOT NULL, + DistributionChannel NVARCHAR(2) NOT NULL, + Division NVARCHAR(2) NOT NULL, + DepartureCountry NVARCHAR(3) NOT NULL, + CustomerTaxCategory NVARCHAR(4) NOT NULL, + CustomerTaxClassification NVARCHAR(1), + PRIMARY KEY(Customer, SalesOrganization, DistributionChannel, Division, DepartureCountry, CustomerTaxCategory) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_CustomerWithHoldingTax ( + Customer NVARCHAR(10) NOT NULL, + CompanyCode NVARCHAR(4) NOT NULL, + WithholdingTaxType NVARCHAR(2) NOT NULL, + WithholdingTaxCode NVARCHAR(2), + WithholdingTaxAgent BOOLEAN, + ObligationDateBegin DATE, + ObligationDateEnd DATE, + WithholdingTaxNumber NVARCHAR(16), + WithholdingTaxCertificate NVARCHAR(25), + WithholdingTaxExmptPercent DECIMAL(5, 2), + ExemptionDateBegin DATE, + ExemptionDateEnd DATE, + ExemptionReason NVARCHAR(2), + AuthorizationGroup NVARCHAR(4), + PRIMARY KEY(Customer, CompanyCode, WithholdingTaxType) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_CustSalesPartnerFunc ( + Customer NVARCHAR(10) NOT NULL, + SalesOrganization NVARCHAR(4) NOT NULL, + DistributionChannel NVARCHAR(2) NOT NULL, + Division NVARCHAR(2) NOT NULL, + PartnerCounter NVARCHAR(3) NOT NULL, + PartnerFunction NVARCHAR(2) NOT NULL, + BPCustomerNumber NVARCHAR(10), + CustomerPartnerDescription NVARCHAR(30), + DefaultPartner BOOLEAN, + AuthorizationGroup NVARCHAR(4), + PRIMARY KEY(Customer, SalesOrganization, DistributionChannel, Division, PartnerCounter, PartnerFunction) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_Supplier ( + Supplier NVARCHAR(10) NOT NULL, + AlternativePayeeAccountNumber NVARCHAR(10), + AuthorizationGroup NVARCHAR(4), + CreatedByUser NVARCHAR(12), + CreationDate DATE, + Customer NVARCHAR(10), + PaymentIsBlockedForSupplier BOOLEAN, + PostingIsBlocked BOOLEAN, + PurchasingIsBlocked BOOLEAN, + SupplierAccountGroup NVARCHAR(4), + SupplierFullName NVARCHAR(220), + SupplierName NVARCHAR(80), + VATRegistration NVARCHAR(20), + BirthDate DATE, + ConcatenatedInternationalLocNo NVARCHAR(20), + DeletionIndicator BOOLEAN, + FiscalAddress NVARCHAR(10), + Industry NVARCHAR(4), + InternationalLocationNumber1 NVARCHAR(7), + InternationalLocationNumber2 NVARCHAR(5), + InternationalLocationNumber3 NVARCHAR(1), + IsNaturalPerson NVARCHAR(1), + ResponsibleType NVARCHAR(2), + SuplrQltyInProcmtCertfnValidTo DATE, + SuplrQualityManagementSystem NVARCHAR(4), + SupplierCorporateGroup NVARCHAR(10), + SupplierProcurementBlock NVARCHAR(2), + TaxNumber1 NVARCHAR(16), + TaxNumber2 NVARCHAR(11), + TaxNumber3 NVARCHAR(18), + TaxNumber4 NVARCHAR(18), + TaxNumber5 NVARCHAR(60), + TaxNumberResponsible NVARCHAR(18), + TaxNumberType NVARCHAR(2), + SuplrProofOfDelivRlvtCode NVARCHAR(1), + BR_TaxIsSplit BOOLEAN, + PRIMARY KEY(Supplier) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_SupplierCompany ( + Supplier NVARCHAR(10) NOT NULL, + CompanyCode NVARCHAR(4) NOT NULL, + AuthorizationGroup NVARCHAR(4), + CompanyCodeName NVARCHAR(25), + PaymentBlockingReason NVARCHAR(1), + SupplierIsBlockedForPosting BOOLEAN, + AccountingClerk NVARCHAR(2), + AccountingClerkFaxNumber NVARCHAR(31), + AccountingClerkPhoneNumber NVARCHAR(30), + SupplierClerk NVARCHAR(15), + SupplierClerkURL NVARCHAR(130), + PaymentMethodsList NVARCHAR(10), + PaymentTerms NVARCHAR(4), + ClearCustomerSupplier BOOLEAN, + IsToBeLocallyProcessed BOOLEAN, + ItemIsToBePaidSeparately BOOLEAN, + PaymentIsToBeSentByEDI BOOLEAN, + HouseBank NVARCHAR(5), + CheckPaidDurationInDays DECIMAL(3, 0), + Currency NVARCHAR(5), + BillOfExchLmtAmtInCoCodeCrcy DECIMAL(14, 3), + SupplierClerkIDBySupplier NVARCHAR(12), + ReconciliationAccount NVARCHAR(10), + InterestCalculationCode NVARCHAR(2), + InterestCalculationDate DATE, + SupplierHeadOffice NVARCHAR(10), + AlternativePayee NVARCHAR(10), + LayoutSortingRule NVARCHAR(3), + APARToleranceGroup NVARCHAR(4), + SupplierCertificationDate DATE, + SupplierAccountNote NVARCHAR(30), + WithholdingTaxCountry NVARCHAR(3), + DeletionIndicator BOOLEAN, + CashPlanningGroup NVARCHAR(10), + IsToBeCheckedForDuplicates BOOLEAN, + MinorityGroup NVARCHAR(3), + SupplierAccountGroup NVARCHAR(4), + PRIMARY KEY(Supplier, CompanyCode) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_SupplierDunning ( + Supplier NVARCHAR(10) NOT NULL, + CompanyCode NVARCHAR(4) NOT NULL, + DunningArea NVARCHAR(2) NOT NULL, + DunningBlock NVARCHAR(1), + DunningLevel NVARCHAR(1), + DunningProcedure NVARCHAR(4), + DunningRecipient NVARCHAR(10), + LastDunnedOn DATE, + LegDunningProcedureOn DATE, + DunningClerk NVARCHAR(2), + AuthorizationGroup NVARCHAR(4), + SupplierAccountGroup NVARCHAR(4), + PRIMARY KEY(Supplier, CompanyCode, DunningArea) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_SupplierPartnerFunc ( + Supplier NVARCHAR(10) NOT NULL, + PurchasingOrganization NVARCHAR(4) NOT NULL, + SupplierSubrange NVARCHAR(6) NOT NULL, + Plant NVARCHAR(4) NOT NULL, + PartnerFunction NVARCHAR(2) NOT NULL, + PartnerCounter NVARCHAR(3) NOT NULL, + DefaultPartner BOOLEAN, + CreationDate DATE, + CreatedByUser NVARCHAR(12), + ReferenceSupplier NVARCHAR(10), + AuthorizationGroup NVARCHAR(4), + PRIMARY KEY(Supplier, PurchasingOrganization, SupplierSubrange, Plant, PartnerFunction, PartnerCounter) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_SupplierPurchasingOrg ( + Supplier NVARCHAR(10) NOT NULL, + PurchasingOrganization NVARCHAR(4) NOT NULL, + CalculationSchemaGroupCode NVARCHAR(2), + DeletionIndicator BOOLEAN, + IncotermsClassification NVARCHAR(3), + IncotermsTransferLocation NVARCHAR(28), + IncotermsVersion NVARCHAR(4), + IncotermsLocation1 NVARCHAR(70), + IncotermsLocation2 NVARCHAR(70), + InvoiceIsGoodsReceiptBased BOOLEAN, + MaterialPlannedDeliveryDurn DECIMAL(3, 0), + MinimumOrderAmount DECIMAL(14, 3), + PaymentTerms NVARCHAR(4), + PricingDateControl NVARCHAR(1), + PurOrdAutoGenerationIsAllowed BOOLEAN, + PurchaseOrderCurrency NVARCHAR(5), + PurchasingGroup NVARCHAR(3), + PurchasingIsBlockedForSupplier BOOLEAN, + ShippingCondition NVARCHAR(2), + SupplierABCClassificationCode NVARCHAR(1), + SupplierPhoneNumber NVARCHAR(16), + SupplierRespSalesPersonName NVARCHAR(30), + AuthorizationGroup NVARCHAR(4), + SupplierAccountGroup NVARCHAR(4), + PRIMARY KEY(Supplier, PurchasingOrganization) +); + +CREATE TABLE API_BUSINESS_PARTNER_A_SupplierWithHoldingTax ( + Supplier NVARCHAR(10) NOT NULL, + CompanyCode NVARCHAR(4) NOT NULL, + WithholdingTaxType NVARCHAR(2) NOT NULL, + ExemptionDateBegin DATE, + ExemptionDateEnd DATE, + ExemptionReason NVARCHAR(2), + IsWithholdingTaxSubject BOOLEAN, + RecipientType NVARCHAR(2), + WithholdingTaxCertificate NVARCHAR(25), + WithholdingTaxCode NVARCHAR(2), + WithholdingTaxExmptPercent DECIMAL(5, 2), + WithholdingTaxNumber NVARCHAR(16), + AuthorizationGroup NVARCHAR(4), + PRIMARY KEY(Supplier, CompanyCode, WithholdingTaxType) +); + +CREATE TABLE Statuses_texts ( + locale NVARCHAR(14) NOT NULL, + code NVARCHAR(255) NOT NULL, + text NVARCHAR(255), + PRIMARY KEY(locale, code) +); + +CREATE TABLE my_bookshop_Books_attachments ( + up__ID NVARCHAR(36) NOT NULL, + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7), + createdBy NVARCHAR(255), + modifiedAt TIMESTAMP(7), + modifiedBy NVARCHAR(255), + content BINARY LARGE OBJECT, + mimeType NVARCHAR(255), + fileName NVARCHAR(255), + contentId NVARCHAR(255), + status NVARCHAR(255), + scannedAt TIMESTAMP(7), + note NVARCHAR(255), + folderId NVARCHAR(255), + repositoryId NVARCHAR(255), + objectId NVARCHAR(255), + PRIMARY KEY(up__ID, ID) +); + +CREATE TABLE my_bookshop_Books_texts ( + ID_texts NVARCHAR(36) NOT NULL, + locale NVARCHAR(14), + ID NVARCHAR(36), + title NVARCHAR(111), + descr NVARCHAR(1111), + PRIMARY KEY(ID_texts), + CONSTRAINT my_bookshop_Books_texts_locale UNIQUE (locale, ID) +); + +CREATE TABLE my_bookshop_Genres_texts ( + locale NVARCHAR(14) NOT NULL, + name NVARCHAR(255), + descr NVARCHAR(1000), + ID INTEGER NOT NULL, + PRIMARY KEY(locale, ID) +); + +CREATE TABLE my_bookshop_Orders_changes ( + up__ID NVARCHAR(36) NOT NULL, + change_ID NVARCHAR(36) NOT NULL, + PRIMARY KEY(up__ID, change_ID) +); + +CREATE TABLE sap_common_Languages_texts ( + locale NVARCHAR(14) NOT NULL, + name NVARCHAR(255), + descr NVARCHAR(1000), + code NVARCHAR(14) NOT NULL, + PRIMARY KEY(locale, code) +); + +CREATE TABLE sap_common_Currencies_texts ( + locale NVARCHAR(14) NOT NULL, + name NVARCHAR(255), + descr NVARCHAR(1000), + code NVARCHAR(3) NOT NULL, + PRIMARY KEY(locale, code) +); + +CREATE TABLE DRAFT_DraftAdministrativeData ( + DraftUUID NVARCHAR(36) NOT NULL, + CreationDateTime TIMESTAMP(7), + CreatedByUser NVARCHAR(256), + DraftIsCreatedByMe BOOLEAN, + LastChangeDateTime TIMESTAMP(7), + LastChangedByUser NVARCHAR(256), + InProcessByUser NVARCHAR(256), + DraftIsProcessedByMe BOOLEAN, + PRIMARY KEY(DraftUUID) +); + +CREATE TABLE AdminService_Books_drafts ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7) NULL, + createdBy NVARCHAR(255) NULL, + modifiedAt TIMESTAMP(7) NULL, + modifiedBy NVARCHAR(255) NULL, + title NVARCHAR(111) NULL, + descr NVARCHAR(1111) NULL, + author_ID NVARCHAR(36) NULL, + genre_ID INTEGER NULL, + stock INTEGER NULL, + price DECIMAL(9, 2) NULL, + currency_code NVARCHAR(3) NULL, + rating DECIMAL(2, 1) NULL, + isReviewable BOOLEAN NULL DEFAULT TRUE, + isbn NVARCHAR(40) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID) +); + +CREATE TABLE AdminService_Books_attachments_drafts ( + up__ID NVARCHAR(36) NOT NULL, + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7) NULL, + createdBy NVARCHAR(255) NULL, + modifiedAt TIMESTAMP(7) NULL, + modifiedBy NVARCHAR(255) NULL, + content BINARY LARGE OBJECT NULL, + mimeType NVARCHAR(255) NULL, + fileName NVARCHAR(255) NULL, + contentId NVARCHAR(255) NULL, + status NVARCHAR(255) NULL, + scannedAt TIMESTAMP(7) NULL, + note NVARCHAR(255) NULL, + folderId NVARCHAR(255) NULL, + repositoryId NVARCHAR(255) NULL, + objectId NVARCHAR(255) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(up__ID, ID) +); + +CREATE TABLE AdminService_Books_texts_drafts ( + ID_texts NVARCHAR(36) NOT NULL, + locale NVARCHAR(14) NULL, + ID NVARCHAR(36) NULL, + title NVARCHAR(111) NULL, + descr NVARCHAR(1111) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID_texts) +); + +CREATE TABLE AdminService_Orders_drafts ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7) NULL, + createdBy NVARCHAR(255) NULL, + modifiedAt TIMESTAMP(7) NULL, + modifiedBy NVARCHAR(255) NULL, + OrderNo NVARCHAR(255) NULL, + buyer NVARCHAR(255) NULL, + total DECIMAL(9, 2) NULL, + currency_code NVARCHAR(3) NULL, + shippingAddress_ID NVARCHAR(10) NULL, + shippingAddress_businessPartner NVARCHAR(10) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID) +); + +CREATE TABLE AdminService_OrderItems_drafts ( + ID NVARCHAR(36) NOT NULL, + parent_ID NVARCHAR(36) NULL, + book_ID NVARCHAR(36) NULL, + quantity INTEGER NULL, + amount DECIMAL(9, 2) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID) +); + +CREATE TABLE NotesService_Notes_drafts ( + ID NVARCHAR(36) NOT NULL, + note NVARCHAR(255) NULL, + address_ID NVARCHAR(10) NULL, + address_businessPartner NVARCHAR(10) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID) +); + +CREATE TABLE ReviewService_Reviews_drafts ( + ID NVARCHAR(36) NOT NULL, + createdAt TIMESTAMP(7) NULL, + createdBy NVARCHAR(255) NULL, + modifiedAt TIMESTAMP(7) NULL, + modifiedBy NVARCHAR(255) NULL, + book_ID NVARCHAR(36) NULL, + rating INTEGER NULL, + title NVARCHAR(111) NULL, + text NVARCHAR(1111) NULL, + IsActiveEntity BOOLEAN, + HasActiveEntity BOOLEAN, + HasDraftEntity BOOLEAN, + DraftAdministrativeData_DraftUUID NVARCHAR(36) NOT NULL, + PRIMARY KEY(ID) +); + +CREATE VIEW AdminService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.createdBy, + Books_0.modifiedAt, + Books_0.modifiedBy, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM my_bookshop_Books AS Books_0; + +CREATE VIEW AdminService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM my_bookshop_Authors AS Authors_0; + +CREATE VIEW AdminService_Orders AS SELECT + Orders_0.ID, + Orders_0.createdAt, + Orders_0.createdBy, + Orders_0.modifiedAt, + Orders_0.modifiedBy, + Orders_0.OrderNo, + Orders_0.buyer, + Orders_0.total, + Orders_0.currency_code, + Orders_0.shippingAddress_ID, + Orders_0.shippingAddress_businessPartner +FROM my_bookshop_Orders AS Orders_0; + +CREATE VIEW AdminService_Languages AS SELECT + CommonLanguages_0.name, + CommonLanguages_0.descr, + CommonLanguages_0.code +FROM sap_common_Languages AS CommonLanguages_0; + +CREATE VIEW CatalogService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.modifiedAt, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM my_bookshop_Books AS Books_0; + +CREATE VIEW CatalogService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM my_bookshop_Authors AS Authors_0; + +CREATE VIEW CatalogService_Reviews AS SELECT + Reviews_0.ID, + Reviews_0.createdAt, + Reviews_0.createdBy, + Reviews_0.modifiedAt, + Reviews_0.modifiedBy, + Reviews_0.book_ID, + Reviews_0.rating, + Reviews_0.title, + Reviews_0.text +FROM my_bookshop_Reviews AS Reviews_0; + +CREATE VIEW my_bookshop_NoteableAddresses AS SELECT + A_BusinessPartnerAddress_0.AddressID AS ID, + A_BusinessPartnerAddress_0.BusinessPartner AS businessPartner, + A_BusinessPartnerAddress_0.Country AS country, + A_BusinessPartnerAddress_0.CityName AS city, + A_BusinessPartnerAddress_0.PostalCode AS postalCode, + A_BusinessPartnerAddress_0.StreetName AS street, + A_BusinessPartnerAddress_0.HouseNumber AS houseNumber +FROM API_BUSINESS_PARTNER_A_BusinessPartnerAddress AS A_BusinessPartnerAddress_0; + +CREATE VIEW NotesService_Notes AS SELECT + Notes_0.ID, + Notes_0.note, + Notes_0.address_ID, + Notes_0.address_businessPartner +FROM my_bookshop_Notes AS Notes_0; + +CREATE VIEW ReviewService_Reviews AS SELECT + Reviews_0.ID, + Reviews_0.createdAt, + Reviews_0.createdBy, + Reviews_0.modifiedAt, + Reviews_0.modifiedBy, + Reviews_0.book_ID, + Reviews_0.rating, + Reviews_0.title, + Reviews_0.text +FROM my_bookshop_Reviews AS Reviews_0; + +CREATE VIEW ReviewService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.modifiedAt, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM my_bookshop_Books AS Books_0; + +CREATE VIEW ReviewService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM my_bookshop_Authors AS Authors_0; + +CREATE VIEW AdminService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM my_bookshop_Genres AS Genres_0; + +CREATE VIEW AdminService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM sap_common_Currencies AS Currencies_0; + +CREATE VIEW AdminService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW AdminService_Books_texts AS SELECT + texts_0.ID_texts, + texts_0.locale, + texts_0.ID, + texts_0.title, + texts_0.descr +FROM my_bookshop_Books_texts AS texts_0; + +CREATE VIEW AdminService_OrderItems AS SELECT + OrderItems_0.ID, + OrderItems_0.parent_ID, + OrderItems_0.book_ID, + OrderItems_0.quantity, + OrderItems_0.amount +FROM my_bookshop_OrderItems AS OrderItems_0; + +CREATE VIEW AdminService_Orders_changes AS SELECT + changes_0.up__ID, + changes_0.change_ID +FROM my_bookshop_Orders_changes AS changes_0; + +CREATE VIEW AdminService_Addresses AS SELECT + Addresses_0.ID, + Addresses_0.businessPartner, + Addresses_0.country, + Addresses_0.city, + Addresses_0.postalCode, + Addresses_0.street, + Addresses_0.houseNumber, + Addresses_0.tombstone +FROM my_bookshop_Addresses AS Addresses_0; + +CREATE VIEW AdminService_Languages_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.code +FROM sap_common_Languages_texts AS texts_0; + +CREATE VIEW CatalogService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM my_bookshop_Genres AS Genres_0; + +CREATE VIEW CatalogService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM sap_common_Currencies AS Currencies_0; + +CREATE VIEW CatalogService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW CatalogService_Books_texts AS SELECT + texts_0.ID_texts, + texts_0.locale, + texts_0.ID, + texts_0.title, + texts_0.descr +FROM my_bookshop_Books_texts AS texts_0; + +CREATE VIEW ReviewService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM my_bookshop_Genres AS Genres_0; + +CREATE VIEW ReviewService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM sap_common_Currencies AS Currencies_0; + +CREATE VIEW ReviewService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW ReviewService_Books_texts AS SELECT + texts_0.ID_texts, + texts_0.locale, + texts_0.ID, + texts_0.title, + texts_0.descr +FROM my_bookshop_Books_texts AS texts_0; + +CREATE VIEW AdminService_Genres_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.ID +FROM my_bookshop_Genres_texts AS texts_0; + +CREATE VIEW AdminService_Currencies_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.code +FROM sap_common_Currencies_texts AS texts_0; + +CREATE VIEW AdminService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM Statuses AS Statuses_0; + +CREATE VIEW AdminService_Changes AS SELECT + Changes_0.ID, + Changes_0.createdAt, + Changes_0.createdBy, + Changes_0.changeLogID, + Changes_0.rootEntity, + Changes_0.rootIdentifier, + Changes_0.attribute, + Changes_0.valueChangedFrom, + Changes_0.valueChangedTo, + Changes_0.valueDataType, + Changes_0.targetIdentifier, + Changes_0.targetEntity, + Changes_0.path, + Changes_0.modification +FROM sap_changelog_Changes AS Changes_0; + +CREATE VIEW CatalogService_Genres_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.ID +FROM my_bookshop_Genres_texts AS texts_0; + +CREATE VIEW CatalogService_Currencies_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.code +FROM sap_common_Currencies_texts AS texts_0; + +CREATE VIEW CatalogService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM Statuses AS Statuses_0; + +CREATE VIEW ReviewService_Genres_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.ID +FROM my_bookshop_Genres_texts AS texts_0; + +CREATE VIEW ReviewService_Currencies_texts AS SELECT + texts_0.locale, + texts_0.name, + texts_0.descr, + texts_0.code +FROM sap_common_Currencies_texts AS texts_0; + +CREATE VIEW ReviewService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM Statuses AS Statuses_0; + +CREATE VIEW AdminService_Statuses_texts AS SELECT + texts_0.locale, + texts_0.code, + texts_0.text +FROM Statuses_texts AS texts_0; + +CREATE VIEW CatalogService_Statuses_texts AS SELECT + texts_0.locale, + texts_0.code, + texts_0.text +FROM Statuses_texts AS texts_0; + +CREATE VIEW ReviewService_Statuses_texts AS SELECT + texts_0.locale, + texts_0.code, + texts_0.text +FROM Statuses_texts AS texts_0; + +CREATE VIEW localized_Statuses AS SELECT + L_0.code, + coalesce(localized_1.text, L_0.text) AS text +FROM (Statuses AS L_0 LEFT JOIN Statuses_texts AS localized_1 ON localized_1.code = L_0.code AND localized_1.locale = @locale); + +CREATE VIEW localized_my_bookshop_Books AS SELECT + L_0.ID, + L_0.createdAt, + L_0.createdBy, + L_0.modifiedAt, + L_0.modifiedBy, + coalesce(localized_1.title, L_0.title) AS title, + coalesce(localized_1.descr, L_0.descr) AS descr, + L_0.author_ID, + L_0.genre_ID, + L_0.stock, + L_0.price, + L_0.currency_code, + L_0.rating, + L_0.isReviewable, + L_0.isbn +FROM (my_bookshop_Books AS L_0 LEFT JOIN my_bookshop_Books_texts AS localized_1 ON localized_1.ID = L_0.ID AND localized_1.locale = @locale); + +CREATE VIEW localized_my_bookshop_Genres AS SELECT + coalesce(localized_1.name, L_0.name) AS name, + coalesce(localized_1.descr, L_0.descr) AS descr, + L_0.ID, + L_0.parent_ID +FROM (my_bookshop_Genres AS L_0 LEFT JOIN my_bookshop_Genres_texts AS localized_1 ON localized_1.ID = L_0.ID AND localized_1.locale = @locale); + +CREATE VIEW localized_sap_common_Languages AS SELECT + coalesce(localized_1.name, L_0.name) AS name, + coalesce(localized_1.descr, L_0.descr) AS descr, + L_0.code +FROM (sap_common_Languages AS L_0 LEFT JOIN sap_common_Languages_texts AS localized_1 ON localized_1.code = L_0.code AND localized_1.locale = @locale); + +CREATE VIEW localized_sap_common_Currencies AS SELECT + coalesce(localized_1.name, L_0.name) AS name, + coalesce(localized_1.descr, L_0.descr) AS descr, + L_0.code, + L_0.symbol, + L_0.minorUnit +FROM (sap_common_Currencies AS L_0 LEFT JOIN sap_common_Currencies_texts AS localized_1 ON localized_1.code = L_0.code AND localized_1.locale = @locale); + +CREATE VIEW localized_my_bookshop_Authors AS SELECT + L.ID, + L.createdAt, + L.createdBy, + L.modifiedAt, + L.modifiedBy, + L.name, + L.dateOfBirth, + L.dateOfDeath, + L.placeOfBirth, + L.placeOfDeath +FROM my_bookshop_Authors AS L; + +CREATE VIEW localized_my_bookshop_Orders AS SELECT + L.ID, + L.createdAt, + L.createdBy, + L.modifiedAt, + L.modifiedBy, + L.OrderNo, + L.buyer, + L.total, + L.currency_code, + L.shippingAddress_ID, + L.shippingAddress_businessPartner +FROM my_bookshop_Orders AS L; + +CREATE VIEW localized_my_bookshop_OrderItems AS SELECT + L.ID, + L.parent_ID, + L.book_ID, + L.quantity, + L.amount +FROM my_bookshop_OrderItems AS L; + +CREATE VIEW localized_my_bookshop_Reviews AS SELECT + L.ID, + L.createdAt, + L.createdBy, + L.modifiedAt, + L.modifiedBy, + L.book_ID, + L.rating, + L.title, + L.text +FROM my_bookshop_Reviews AS L; + +CREATE VIEW localized_my_bookshop_Books_attachments AS SELECT + L.up__ID, + L.ID, + L.createdAt, + L.createdBy, + L.modifiedAt, + L.modifiedBy, + L.content, + L.mimeType, + L.fileName, + L.contentId, + L.status, + L.scannedAt, + L.note, + L.folderId, + L.repositoryId, + L.objectId +FROM my_bookshop_Books_attachments AS L; + +CREATE VIEW localized_my_bookshop_Orders_changes AS SELECT + L.up__ID, + L.change_ID +FROM my_bookshop_Orders_changes AS L; + +CREATE VIEW AdminService_DraftAdministrativeData AS SELECT + DraftAdministrativeData.DraftUUID, + DraftAdministrativeData.CreationDateTime, + DraftAdministrativeData.CreatedByUser, + DraftAdministrativeData.DraftIsCreatedByMe, + DraftAdministrativeData.LastChangeDateTime, + DraftAdministrativeData.LastChangedByUser, + DraftAdministrativeData.InProcessByUser, + DraftAdministrativeData.DraftIsProcessedByMe +FROM DRAFT_DraftAdministrativeData AS DraftAdministrativeData; + +CREATE VIEW NotesService_DraftAdministrativeData AS SELECT + DraftAdministrativeData.DraftUUID, + DraftAdministrativeData.CreationDateTime, + DraftAdministrativeData.CreatedByUser, + DraftAdministrativeData.DraftIsCreatedByMe, + DraftAdministrativeData.LastChangeDateTime, + DraftAdministrativeData.LastChangedByUser, + DraftAdministrativeData.InProcessByUser, + DraftAdministrativeData.DraftIsProcessedByMe +FROM DRAFT_DraftAdministrativeData AS DraftAdministrativeData; + +CREATE VIEW ReviewService_DraftAdministrativeData AS SELECT + DraftAdministrativeData.DraftUUID, + DraftAdministrativeData.CreationDateTime, + DraftAdministrativeData.CreatedByUser, + DraftAdministrativeData.DraftIsCreatedByMe, + DraftAdministrativeData.LastChangeDateTime, + DraftAdministrativeData.LastChangedByUser, + DraftAdministrativeData.InProcessByUser, + DraftAdministrativeData.DraftIsProcessedByMe +FROM DRAFT_DraftAdministrativeData AS DraftAdministrativeData; + +CREATE VIEW NotesService_Addresses AS SELECT + NoteableAddresses_0.ID, + NoteableAddresses_0.businessPartner, + NoteableAddresses_0.country, + NoteableAddresses_0.city, + NoteableAddresses_0.postalCode, + NoteableAddresses_0.street, + NoteableAddresses_0.houseNumber +FROM my_bookshop_NoteableAddresses AS NoteableAddresses_0; + +CREATE VIEW localized_AdminService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.createdBy, + Books_0.modifiedAt, + Books_0.modifiedBy, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM localized_my_bookshop_Books AS Books_0; + +CREATE VIEW localized_AdminService_Languages AS SELECT + CommonLanguages_0.name, + CommonLanguages_0.descr, + CommonLanguages_0.code +FROM localized_sap_common_Languages AS CommonLanguages_0; + +CREATE VIEW localized_CatalogService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.modifiedAt, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM localized_my_bookshop_Books AS Books_0; + +CREATE VIEW localized_ReviewService_Books AS SELECT + Books_0.ID, + Books_0.createdAt, + Books_0.modifiedAt, + Books_0.title, + Books_0.descr, + Books_0.author_ID, + Books_0.genre_ID, + Books_0.stock, + Books_0.price, + Books_0.currency_code, + Books_0.rating, + Books_0.isReviewable, + Books_0.isbn +FROM localized_my_bookshop_Books AS Books_0; + +CREATE VIEW localized_AdminService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM localized_my_bookshop_Genres AS Genres_0; + +CREATE VIEW localized_AdminService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM localized_sap_common_Currencies AS Currencies_0; + +CREATE VIEW localized_CatalogService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM localized_my_bookshop_Genres AS Genres_0; + +CREATE VIEW localized_CatalogService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM localized_sap_common_Currencies AS Currencies_0; + +CREATE VIEW localized_ReviewService_Genres AS SELECT + Genres_0.name, + Genres_0.descr, + Genres_0.ID, + Genres_0.parent_ID +FROM localized_my_bookshop_Genres AS Genres_0; + +CREATE VIEW localized_ReviewService_Currencies AS SELECT + Currencies_0.name, + Currencies_0.descr, + Currencies_0.code, + Currencies_0.symbol, + Currencies_0.minorUnit +FROM localized_sap_common_Currencies AS Currencies_0; + +CREATE VIEW localized_AdminService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM localized_Statuses AS Statuses_0; + +CREATE VIEW localized_CatalogService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM localized_Statuses AS Statuses_0; + +CREATE VIEW localized_ReviewService_Statuses AS SELECT + Statuses_0.code, + Statuses_0.text +FROM localized_Statuses AS Statuses_0; + +CREATE VIEW localized_AdminService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM localized_my_bookshop_Authors AS Authors_0; + +CREATE VIEW localized_AdminService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM localized_my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW localized_AdminService_OrderItems AS SELECT + OrderItems_0.ID, + OrderItems_0.parent_ID, + OrderItems_0.book_ID, + OrderItems_0.quantity, + OrderItems_0.amount +FROM localized_my_bookshop_OrderItems AS OrderItems_0; + +CREATE VIEW localized_CatalogService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM localized_my_bookshop_Authors AS Authors_0; + +CREATE VIEW localized_CatalogService_Reviews AS SELECT + Reviews_0.ID, + Reviews_0.createdAt, + Reviews_0.createdBy, + Reviews_0.modifiedAt, + Reviews_0.modifiedBy, + Reviews_0.book_ID, + Reviews_0.rating, + Reviews_0.title, + Reviews_0.text +FROM localized_my_bookshop_Reviews AS Reviews_0; + +CREATE VIEW localized_CatalogService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM localized_my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW localized_ReviewService_Reviews AS SELECT + Reviews_0.ID, + Reviews_0.createdAt, + Reviews_0.createdBy, + Reviews_0.modifiedAt, + Reviews_0.modifiedBy, + Reviews_0.book_ID, + Reviews_0.rating, + Reviews_0.title, + Reviews_0.text +FROM localized_my_bookshop_Reviews AS Reviews_0; + +CREATE VIEW localized_ReviewService_Authors AS SELECT + Authors_0.ID, + Authors_0.createdAt, + Authors_0.createdBy, + Authors_0.modifiedAt, + Authors_0.modifiedBy, + Authors_0.name, + Authors_0.dateOfBirth, + Authors_0.dateOfDeath, + Authors_0.placeOfBirth, + Authors_0.placeOfDeath +FROM localized_my_bookshop_Authors AS Authors_0; + +CREATE VIEW localized_ReviewService_Books_attachments AS SELECT + attachments_0.up__ID, + attachments_0.ID, + attachments_0.createdAt, + attachments_0.createdBy, + attachments_0.modifiedAt, + attachments_0.modifiedBy, + attachments_0.content, + attachments_0.mimeType, + attachments_0.fileName, + attachments_0.contentId, + attachments_0.status, + attachments_0.scannedAt, + attachments_0.note, + attachments_0.folderId, + attachments_0.repositoryId, + attachments_0.objectId +FROM localized_my_bookshop_Books_attachments AS attachments_0; + +CREATE VIEW localized_AdminService_Orders AS SELECT + Orders_0.ID, + Orders_0.createdAt, + Orders_0.createdBy, + Orders_0.modifiedAt, + Orders_0.modifiedBy, + Orders_0.OrderNo, + Orders_0.buyer, + Orders_0.total, + Orders_0.currency_code, + Orders_0.shippingAddress_ID, + Orders_0.shippingAddress_businessPartner +FROM localized_my_bookshop_Orders AS Orders_0; + +CREATE VIEW localized_AdminService_Orders_changes AS SELECT + changes_0.up__ID, + changes_0.change_ID +FROM localized_my_bookshop_Orders_changes AS changes_0; + diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/swagger/index.html b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/swagger/index.html new file mode 100644 index 000000000..c1f761271 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/main/resources/swagger/index.html @@ -0,0 +1,93 @@ + + + + + + Swagger UI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddressITestBase.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddressITestBase.java new file mode 100644 index 000000000..ed718019d --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddressITestBase.java @@ -0,0 +1,114 @@ +package my.bookshop; + +import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.HttpHeaders; +import org.springframework.test.web.reactive.server.WebTestClient; + +import com.sap.cds.services.changeset.ChangeSetListener; + +import cds.gen.adminservice.Orders; +import cds.gen.api_business_partner.ABusinessPartnerAddress; +import cds.gen.api_business_partner.ApiBusinessPartner; +import cds.gen.api_business_partner.ApiBusinessPartner_; +import cds.gen.api_business_partner.BusinessPartnerChangedContext; + +public class AdminServiceAddressITestBase { + + private static final String ordersURI = "/api/admin/Orders"; + private static final String orderURI = ordersURI + "(IsActiveEntity=true,ID=%s)"; + private static final String addressesURI = "/api/admin/Addresses"; + private static final String remoteAddressURI = "/api/API_BUSINESS_PARTNER/A_BusinessPartnerAddress(BusinessPartner='%s',AddressID='%s')"; + + @Autowired + private WebTestClient client; + + @Autowired + @Qualifier(ApiBusinessPartner_.CDS_NAME) + private ApiBusinessPartner bupa; + + public void testAddressesValueHelp() { + client.get().uri(addressesURI).headers(this::adminCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.['@context']").isEqualTo("$metadata#Addresses") + .jsonPath("$.value[0].ID").isEqualTo("100") + .jsonPath("$.value[0].businessPartner").isEqualTo("10401010") + .jsonPath("$.value[1].ID").isEqualTo("200") + .jsonPath("$.value[1].businessPartner").isEqualTo("10401010") + .jsonPath("$.value[2].ID").isEqualTo("300") + .jsonPath("$.value[2].businessPartner").isEqualTo("10401010"); + } + + public void testOrderWithAddress() throws InterruptedException { + Orders order = Orders.create(); + order.setOrderNo("1337"); + order.setShippingAddressId("100"); + + String id = UUID.randomUUID().toString(); + client.put().uri(String.format(orderURI, id)) + .headers(this::adminCredentials) + .header("Content-Type", "application/json") + .bodyValue(order.toJson()) + .exchange() + .expectStatus().isCreated(); + + client.get().uri(String.format(orderURI, id) + "?$expand=shippingAddress").headers(this::adminCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.ID").isEqualTo(id) + .jsonPath("$.OrderNo").isEqualTo(order.getOrderNo()) + .jsonPath("$.shippingAddress.ID").isEqualTo("100") + .jsonPath("$.shippingAddress.businessPartner").isEqualTo("10401010") + .jsonPath("$.shippingAddress.houseNumber").isEqualTo("16"); + + client.get().uri(String.format(orderURI, id) + "/shippingAddress").headers(this::adminCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.ID").isEqualTo("100") + .jsonPath("$.businessPartner").isEqualTo("10401010") + .jsonPath("$.houseNumber").isEqualTo("16"); + + // react on remote address update + CountDownLatch latch = new CountDownLatch(1); + bupa.on(BusinessPartnerChangedContext.CDS_NAME, null, (context) -> context.getChangeSetContext().register(new ChangeSetListener(){ + + @Override + public void afterClose(boolean completed) { + latch.countDown(); + } + + })); + + // update remote address + ABusinessPartnerAddress address = ABusinessPartnerAddress.create(); + address.setHouseNumber("17"); + + client.patch().uri(String.format(remoteAddressURI, "10401010", "100")).headers(this::authenticatedCredentials) + .header("Content-Type", "application/json") + .bodyValue(address.toJson()) + .exchange() + .expectStatus().isOk(); + + // wait for remote address update + latch.await(30, TimeUnit.SECONDS); + client.get().uri(String.format(orderURI, id) + "/shippingAddress").headers(this::adminCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.ID").isEqualTo("100") + .jsonPath("$.businessPartner").isEqualTo("10401010") + .jsonPath("$.houseNumber").isEqualTo("17"); + } + + private void adminCredentials(HttpHeaders headers) { + headers.setBasicAuth("admin", "admin"); + } + + private void authenticatedCredentials(HttpHeaders headers) { + headers.setBasicAuth("authenticated", ""); + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddress_default_ITest.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddress_default_ITest.java new file mode 100644 index 000000000..42b094538 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddress_default_ITest.java @@ -0,0 +1,29 @@ +package my.bookshop; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.test.context.ActiveProfiles; + +/** + * Runs tests defined in {@link AdminServiceAddressITestBase} with the default profile. + * The default profile doesn't create any remote services, so the application behaves as if + * the AdminService and the API_BUSINESS_PARTNER service were provided by the same application. + */ +@ActiveProfiles("default") +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +public class AdminServiceAddress_default_ITest extends AdminServiceAddressITestBase { + + @Test + @Override + public void testAddressesValueHelp() { + super.testAddressesValueHelp(); + } + + @Test + @Override + public void testOrderWithAddress() throws InterruptedException { + super.testOrderWithAddress(); + } + +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddress_mocked_ITest.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddress_mocked_ITest.java new file mode 100644 index 000000000..d363f824f --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceAddress_mocked_ITest.java @@ -0,0 +1,30 @@ +package my.bookshop; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.test.context.ActiveProfiles; + +/** + * Runs tests defined in {@link AdminServiceAddressITestBase} with the default and mocked profile. + * The mocked profile creates a remote services for the API_BUSINESS_PARTNER service (which is however mocked by our own application), + * so the application behaves as if the AdminService and the API_BUSINESS_PARTNER service were provided by two different applications. + */ +@ActiveProfiles({"default", "mocked"}) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, + properties = "cds.remote.services.'[API_BUSINESS_PARTNER]'.destination.name=myself-AdminServiceAddressITest") +public class AdminServiceAddress_mocked_ITest extends AdminServiceAddressITestBase { + + @Test + @Override + public void testAddressesValueHelp() { + super.testAddressesValueHelp(); + } + + @Test + @Override + public void testOrderWithAddress() throws InterruptedException { + super.testOrderWithAddress(); + } + +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceTest.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceTest.java new file mode 100644 index 000000000..2c0cba173 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/AdminServiceTest.java @@ -0,0 +1,96 @@ +package my.bookshop; + +import static cds.gen.adminservice.AdminService_.AUTHORS; +import static cds.gen.adminservice.AdminService_.ORDERS; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.math.BigDecimal; +import java.util.Collections; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.test.context.support.WithMockUser; + +import com.sap.cds.Result; +import com.sap.cds.ql.Insert; +import com.sap.cds.services.ServiceException; +import com.sap.cds.services.utils.CdsErrorStatuses; + +import cds.gen.adminservice.AdminService; +import cds.gen.adminservice.Authors; +import cds.gen.adminservice.OrderItems; +import cds.gen.adminservice.Orders; + +@SpringBootTest +@AutoConfigureMockMvc +public class AdminServiceTest { + + @Autowired + private AdminService.Draft adminService; + + @Test + @WithMockUser(username = "user") + public void testUnauthorizedAccess() { + assertThrows(ServiceException.class, () -> { + adminService.newDraft(Insert.into(AUTHORS).entry(Collections.emptyMap())); + }); + } + + @Test + @WithMockUser(username = "admin") + public void testInvalidAuthorName() { + assertThrows(ServiceException.class, () -> { + Authors author = Authors.create(); + author.setName("little Joey"); + adminService.run(Insert.into(AUTHORS).entry(author)); + }); + } + + @Test + @WithMockUser(username = "admin") + public void testValidAuthorName() { + Authors author = Authors.create(); + author.setName("Big Joey"); + Result result = adminService.run(Insert.into(AUTHORS).entry(author)); + assertEquals(1, result.rowCount()); + } + + @Test + @WithMockUser(username = "admin") + void testCreateOrderWithoutBook() { + Orders order = Orders.create(); + order.setOrderNo("324"); + order.setShippingAddressId("100"); + OrderItems item = OrderItems.create(); + item.setQuantity(1); + item.setAmount(BigDecimal.valueOf(12.12)); + order.setItems(Collections.singletonList(item)); + + // Runtime ensures that book is present in the order item, when it is created. + ServiceException exception = + assertThrows(ServiceException.class, () -> adminService.run(Insert.into(ORDERS).entry(order))); + assertEquals(CdsErrorStatuses.VALUE_REQUIRED.getCodeString(), exception.getErrorStatus().getCodeString()); + } + + @Test + @WithMockUser(username = "admin") + void testCreateOrderWithNonExistingBook() { + Orders order = Orders.create(); + order.setOrderNo("324"); + order.setShippingAddressId("100"); + OrderItems item = OrderItems.create(); + item.setQuantity(1); + item.setAmount(BigDecimal.valueOf(12.12)); + item.setBookId("4a519e61-3c3a-4bd9-ab12-d7e0c5ddaabb"); + order.setItems(Collections.singletonList(item)); + + // Runtime ensures that book exists when order item is created. + ServiceException exception = + assertThrows(ServiceException.class, () -> adminService.run(Insert.into(ORDERS).entry(order))); + assertEquals(CdsErrorStatuses.TARGET_ENTITY_MISSING.getCodeString(), exception.getErrorStatus().getCodeString()); + } + +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/CatalogServiceITest.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/CatalogServiceITest.java new file mode 100644 index 000000000..a3010a370 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/CatalogServiceITest.java @@ -0,0 +1,93 @@ +package my.bookshop; + +import static cds.gen.catalogservice.CatalogService_.REVIEWS; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.not; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; + +import com.sap.cds.ql.Delete; +import com.sap.cds.services.persistence.PersistenceService; + +import cds.gen.catalogservice.Reviews; + +@SpringBootTest +@AutoConfigureMockMvc +public class CatalogServiceITest { + + private static final String booksURI = "/api/browse/Books"; + private static final String addReviewURI = String.format("%s(ID=%s)/CatalogService.addReview", booksURI, "f846b0b9-01d4-4f6d-82a4-d79204f62278"); + + private static final String USER_USER_STRING = "user"; + private static final String ADMIN_USER_STRING = "admin"; + + @Autowired + private MockMvc mockMvc; + + @Autowired + private PersistenceService db; + + @AfterEach + public void cleanup() { + db.run(Delete.from(REVIEWS)); + } + + @Test + public void testDiscountApplied() throws Exception { + mockMvc.perform(get(booksURI + "?$filter=stock gt 200&top=1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.value[0].title").value(containsString("11% discount"))); + } + + @Test + public void testDiscountNotApplied() throws Exception { + mockMvc.perform(get(booksURI + "?$filter=stock lt 100&top=1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.value[0].title").value(not(containsString("11% discount")))); + } + + @Test + public void testCreateReviewNotAuthenticated() throws Exception { + String payload = createTestReview().toJson(); + mockMvc.perform(post(addReviewURI).contentType(MediaType.APPLICATION_JSON).content(payload)) + .andExpect(status().isUnauthorized()); + } + + @Test + @WithMockUser(USER_USER_STRING) + public void testCreateReviewByUser() throws Exception { + String payload = createTestReview().toJson(); + mockMvc.perform(post(addReviewURI).contentType(MediaType.APPLICATION_JSON).content(payload)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.createdBy").value(USER_USER_STRING)); + } + + @Test + @WithMockUser(ADMIN_USER_STRING) + public void testCreateReviewByAdmin() throws Exception { + String payload = createTestReview().toJson(); + mockMvc.perform(post(addReviewURI).contentType(MediaType.APPLICATION_JSON).content(payload)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.createdBy").value(ADMIN_USER_STRING)); + } + + private Reviews createTestReview() { + Reviews review = Reviews.create(); + review.setRating(1); + review.setTitle("title"); + review.setText("text"); + return review; + } + +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/CatalogServiceTest.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/CatalogServiceTest.java new file mode 100644 index 000000000..85684e60b --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/CatalogServiceTest.java @@ -0,0 +1,138 @@ +package my.bookshop; + +import static cds.gen.catalogservice.CatalogService_.BOOKS; +import static cds.gen.catalogservice.CatalogService_.REVIEWS; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.stream.Stream; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.test.context.support.WithMockUser; + +import com.sap.cds.ql.CQL; +import com.sap.cds.ql.Delete; +import com.sap.cds.services.ServiceException; +import com.sap.cds.services.persistence.PersistenceService; + +import cds.gen.catalogservice.Books_; +import cds.gen.catalogservice.CatalogService; +import cds.gen.catalogservice.Reviews; + +@SpringBootTest +public class CatalogServiceTest { + + @Autowired + private CatalogService catalogService; + + @Autowired + private PersistenceService db; + + @AfterEach + public void cleanup() { + db.run(Delete.from(REVIEWS)); + } + + @Test + @WithMockUser(username = "user") + public void testCreateReviewHandler() { + Stream bookReviews = Stream.of( + createReview("f846b0b9-01d4-4f6d-82a4-d79204f62278", 1, "quite bad", "disappointing..."), + createReview("aebdfc8a-0dfa-4468-bd36-48aabd65e663", 5, "great read", "just amazing...")); + + bookReviews.forEach(bookReview -> { + + Books_ ref = CQL.entity(BOOKS).filter(b -> b.ID().eq(bookReview.getBookId())); + Reviews result = catalogService.addReview(ref, bookReview.getRating(), bookReview.getTitle(), bookReview.getText()); + + assertEquals(bookReview.getBookId(), result.getBookId()); + assertEquals(bookReview.getRating(), result.getRating()); + assertEquals(bookReview.getTitle(), result.getTitle()); + assertEquals(bookReview.getText(), result.getText()); + }); + } + + @Test + @WithMockUser(username = "user") + public void testAddReviewWithInvalidRating() { + Stream bookReviews = Stream.of( + // lt 1 is invalid + createReview("f846b0b9-01d4-4f6d-82a4-d79204f62278", 0, "quite bad", "disappointing..."), + // gt 5 is invalid + createReview("9b084139-0b1e-43b6-b12a-7b3669d75f02", 6, "great read", "just amazing...")); + + String message = "Valid rating range needs to be within 1 and 5"; + + bookReviews.forEach(bookReview -> { + Books_ ref = CQL.entity(BOOKS).filter(b -> b.ID().eq(bookReview.getBookId())); + assertThrows(ServiceException.class, () -> catalogService.addReview(ref, bookReview.getRating(), + bookReview.getTitle(), bookReview.getText()), message); + }); + } + + @Test + @WithMockUser(username = "user") + public void testAddReviewForNonExistingBook() { + + String nonExistingBookId = "non-existing"; + String exMessage1 = "You have to specify the book to review"; + String exMessage2 = String.format("A book with the specified ID '%s' does not exist", nonExistingBookId); + + Stream testCases = Stream.of( + // no book provided + new BookReviewTestFixture(createReview(null, 1, "quite bad", "disappointing..."), exMessage1), + // invalid book id + new BookReviewTestFixture(createReview(nonExistingBookId, 5, "great read", "just amazing..."), + exMessage2)); + + testCases.forEach(testCase -> { + Books_ ref = CQL.entity(BOOKS).filter(b -> b.ID().eq(testCase.review.getBookId())); + assertThrows(ServiceException.class, () -> catalogService.addReview(ref, testCase.review.getRating(), + testCase.review.getTitle(), testCase.review.getText()), testCase.exceptionMessage); + }); + } + + @Test + @WithMockUser(username = "user") + public void testAddReviewSameBookMoreThanOnceBySameUser() { + + String bookId = "4a519e61-3c3a-4bd9-ab12-d7e0c5329933"; + Books_ ref = CQL.entity(BOOKS).filter(b -> b.ID().eq(bookId)); + + assertDoesNotThrow(() -> catalogService.addReview(ref, 1, "quite bad", "disappointing...")); + assertThrows(ServiceException.class, () -> catalogService.addReview(ref, 5, "great read", "just amazing..."), + "User not allowed to add more than one review for a given book"); + + String anotherBookId = "9b084139-0b1e-43b6-b12a-7b3669d75f02"; + Books_ anotherRef = CQL.entity(BOOKS).filter(b -> b.ID().eq(anotherBookId)); + + assertDoesNotThrow(() -> catalogService.addReview(anotherRef, 4, "very good", "entertaining...")); + } + + private Reviews createReview(String bookId, Integer rating, String title, String text) { + Reviews review = Reviews.create(); + review.setBookId(bookId); + review.setRating(rating); + review.setTitle(title); + review.setText(text); + return review; + } + + /* + * Holder class for a book review test case. + */ + private class BookReviewTestFixture { + Reviews review; + String exceptionMessage; + + BookReviewTestFixture(Reviews review, String exceptionMessage) { + this.review = review; + this.exceptionMessage = exceptionMessage; + } + } + +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/NotesServiceITest.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/NotesServiceITest.java new file mode 100644 index 000000000..540be4e89 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/NotesServiceITest.java @@ -0,0 +1,192 @@ +package my.bookshop; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.http.HttpHeaders; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.reactive.server.WebTestClient; + +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, + properties = "cds.remote.services.'[API_BUSINESS_PARTNER]'.destination.name=myself-NotesServiceITest") +@ActiveProfiles({"default", "mocked"}) +public class NotesServiceITest { + + private static final String notesURI = "/api/notes/Notes"; + private static final String addressesURI = "/api/notes/Addresses"; + + @Autowired + private WebTestClient client; + + @Test + public void testGetNotes() throws Exception { + client.get().uri(notesURI).headers(this::authenticatedCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.['@context']").isEqualTo("$metadata#Notes") + .jsonPath("$.value[0].ID").isEqualTo("5efc842c-c70d-4ee2-af1d-81c7d257aff7") + .jsonPath("$.value[0].note").isEqualTo("Ring at building 8") + .jsonPath("$.value[0].address_businessPartner").isEqualTo("1000020") + .jsonPath("$.value[0].address_ID").isEqualTo("500") + .jsonPath("$.value[1].ID").isEqualTo("83e2643b-aecc-47d3-9f85-a8ba14eff07d") + .jsonPath("$.value[1].note").isEqualTo("Packages can be dropped off at the reception") + .jsonPath("$.value[1].address_businessPartner").isEqualTo("10401010") + .jsonPath("$.value[1].address_ID").isEqualTo("100") + .jsonPath("$.value[2].ID").isEqualTo("880147b0-8d2d-4ef8-bb52-ae5ae6002fc5") + .jsonPath("$.value[2].note").isEqualTo("Don't deliver packages after 5pm") + .jsonPath("$.value[2].address_businessPartner").isEqualTo("10401010") + .jsonPath("$.value[2].address_ID").isEqualTo("100"); + } + + @Test + public void testGetAddresses() throws Exception { + client.get().uri(addressesURI + "?$filter=businessPartner eq '10401010'").headers(this::authenticatedCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.['@context']").isEqualTo("$metadata#Addresses") + .jsonPath("$.value[0].ID").isEqualTo("100") + .jsonPath("$.value[0].postalCode").isEqualTo("68199") + .jsonPath("$.value[1].ID").isEqualTo("200") + .jsonPath("$.value[1].postalCode").isEqualTo("68789") + .jsonPath("$.value[2].ID").isEqualTo("300") + .jsonPath("$.value[2].postalCode").isEqualTo("14469"); + } + + @Test + public void testGetNoteWithAddress() throws Exception { + client.get().uri(notesURI + "?$expand=address").headers(this::authenticatedCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.['@context']").isEqualTo("$metadata#Notes(address())") + .jsonPath("$.value[0].ID").isEqualTo("5efc842c-c70d-4ee2-af1d-81c7d257aff7") + .jsonPath("$.value[0].note").isEqualTo("Ring at building 8") + .jsonPath("$.value[0].address_businessPartner").isEqualTo("1000020") + .jsonPath("$.value[0].address_ID").isEqualTo("500") + .jsonPath("$.value[0].address.businessPartner").isEqualTo("1000020") + .jsonPath("$.value[0].address.ID").isEqualTo("500") + .jsonPath("$.value[0].address.postalCode").isEqualTo("94304") + .jsonPath("$.value[1].ID").isEqualTo("83e2643b-aecc-47d3-9f85-a8ba14eff07d") + .jsonPath("$.value[1].note").isEqualTo("Packages can be dropped off at the reception") + .jsonPath("$.value[1].address_businessPartner").isEqualTo("10401010") + .jsonPath("$.value[1].address_ID").isEqualTo("100") + .jsonPath("$.value[1].address.businessPartner").isEqualTo("10401010") + .jsonPath("$.value[1].address.ID").isEqualTo("100") + .jsonPath("$.value[1].address.postalCode").isEqualTo("68199") + .jsonPath("$.value[2].ID").isEqualTo("880147b0-8d2d-4ef8-bb52-ae5ae6002fc5") + .jsonPath("$.value[2].note").isEqualTo("Don't deliver packages after 5pm") + .jsonPath("$.value[2].address_businessPartner").isEqualTo("10401010") + .jsonPath("$.value[2].address_ID").isEqualTo("100") + .jsonPath("$.value[2].address.businessPartner").isEqualTo("10401010") + .jsonPath("$.value[2].address.ID").isEqualTo("100") + .jsonPath("$.value[2].address.postalCode").isEqualTo("68199"); + } + + @Test + public void testGetSuppliersWithNotes() throws Exception { + client.get().uri(addressesURI + "?$expand=notes($orderby=ID)&$filter=businessPartner eq '10401010'").headers(this::authenticatedCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.['@context']").isEqualTo("$metadata#Addresses(notes())") + .jsonPath("$.value[0].ID").isEqualTo("100") + .jsonPath("$.value[0].postalCode").isEqualTo("68199") + .jsonPath("$.value[0].notes[0].ID").isEqualTo("83e2643b-aecc-47d3-9f85-a8ba14eff07d") + .jsonPath("$.value[0].notes[0].note").isEqualTo("Packages can be dropped off at the reception") + .jsonPath("$.value[0].notes[0].address_businessPartner").isEqualTo("10401010") + .jsonPath("$.value[0].notes[0].address_ID").isEqualTo("100") + .jsonPath("$.value[0].notes[1].ID").isEqualTo("880147b0-8d2d-4ef8-bb52-ae5ae6002fc5") + .jsonPath("$.value[0].notes[1].note").isEqualTo("Don't deliver packages after 5pm") + .jsonPath("$.value[0].notes[1].address_businessPartner").isEqualTo("10401010") + .jsonPath("$.value[0].notes[1].address_ID").isEqualTo("100") + .jsonPath("$.value[0].notes[2]").doesNotExist() + .jsonPath("$.value[1].ID").isEqualTo("200") + .jsonPath("$.value[1].postalCode").isEqualTo("68789") + .jsonPath("$.value[2].notes").isEmpty() + .jsonPath("$.value[2].ID").isEqualTo("300") + .jsonPath("$.value[2].postalCode").isEqualTo("14469") + .jsonPath("$.value[2].notes").isEmpty(); + } + + @Test + public void testGetNotesToSupplier() throws Exception { + client.get().uri(notesURI + "(ID=5efc842c-c70d-4ee2-af1d-81c7d257aff7,IsActiveEntity=true)/address").headers(this::authenticatedCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.['@context']").isEqualTo("$metadata#Addresses/$entity") + .jsonPath("$.businessPartner").isEqualTo("1000020") + .jsonPath("$.ID").isEqualTo("500") + .jsonPath("$.postalCode").isEqualTo("94304"); + } + + @Test + public void testGetSupplierToNotes() throws Exception { + client.get().uri(addressesURI + "(businessPartner='10401010',ID='100')/notes").headers(this::authenticatedCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.value[0].ID").isEqualTo("83e2643b-aecc-47d3-9f85-a8ba14eff07d") + .jsonPath("$.value[0].note").isEqualTo("Packages can be dropped off at the reception") + .jsonPath("$.value[0].address_businessPartner").isEqualTo("10401010") + .jsonPath("$.value[0].address_ID").isEqualTo("100") + .jsonPath("$.value[1].ID").isEqualTo("880147b0-8d2d-4ef8-bb52-ae5ae6002fc5") + .jsonPath("$.value[1].note").isEqualTo("Don't deliver packages after 5pm") + .jsonPath("$.value[1].address_businessPartner").isEqualTo("10401010") + .jsonPath("$.value[1].address_ID").isEqualTo("100") + .jsonPath("$.value[2]").doesNotExist(); + } + + @Test + public void testGetSupplierToSpecificNote() throws Exception { + client.get().uri(addressesURI + "(businessPartner='10401010',ID='100')/notes(ID=83e2643b-aecc-47d3-9f85-a8ba14eff07d,IsActiveEntity=true)") + .headers(this::authenticatedCredentials) + .exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.ID").isEqualTo("83e2643b-aecc-47d3-9f85-a8ba14eff07d") + .jsonPath("$.note").isEqualTo("Packages can be dropped off at the reception") + .jsonPath("$.address_businessPartner").isEqualTo("10401010") + .jsonPath("$.address_ID").isEqualTo("100"); + } + + @Test + public void testGetNotesWithNestedExpands() throws Exception { + client.get().uri(notesURI + "?$select=note&$expand=address($select=postalCode;$expand=notes($select=note))&$top=1").headers(this::authenticatedCredentials).exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.value[0].ID").isEqualTo("5efc842c-c70d-4ee2-af1d-81c7d257aff7") + .jsonPath("$.value[0].note").isEqualTo("Ring at building 8") + .jsonPath("$.value[0].address.businessPartner").isEqualTo("1000020") + .jsonPath("$.value[0].address.ID").isEqualTo("500") + .jsonPath("$.value[0].address.postalCode").isEqualTo("94304") + .jsonPath("$.value[0].address.notes[0].ID").isEqualTo("5efc842c-c70d-4ee2-af1d-81c7d257aff7") + .jsonPath("$.value[0].address.notes[0].note").isEqualTo("Ring at building 8") + .jsonPath("$.value[0].address.notes[1]").doesNotExist() + .jsonPath("$.value[1]").doesNotExist(); + } + + @Test + public void testGetAddressesWithNestedExpands() throws Exception { + client.get().uri(addressesURI + "?$select=postalCode&$expand=notes($select=note;$expand=address($select=postalCode))&$filter=businessPartner eq '1000020'") + .headers(this::authenticatedCredentials) + .exchange() + .expectStatus().isOk() + .expectBody() + .jsonPath("$.value[0].businessPartner").isEqualTo("1000020") + .jsonPath("$.value[0].ID").isEqualTo("400") + .jsonPath("$.value[0].postalCode").isEqualTo("19073") + .jsonPath("$.value[0].notes").isEmpty() + .jsonPath("$.value[1].businessPartner").isEqualTo("1000020") + .jsonPath("$.value[1].ID").isEqualTo("500") + .jsonPath("$.value[1].postalCode").isEqualTo("94304") + .jsonPath("$.value[1].notes[0].ID").isEqualTo("5efc842c-c70d-4ee2-af1d-81c7d257aff7") + .jsonPath("$.value[1].notes[0].note").isEqualTo("Ring at building 8") + .jsonPath("$.value[1].notes[0].address.businessPartner").isEqualTo("1000020") + .jsonPath("$.value[1].notes[0].address.ID").isEqualTo("500") + .jsonPath("$.value[1].notes[0].address.postalCode").isEqualTo("94304") + .jsonPath("$.value[1].notes[1]").doesNotExist() + .jsonPath("$.value[2]").doesNotExist(); + } + + private void authenticatedCredentials(HttpHeaders headers) { + headers.setBasicAuth("authenticated", ""); + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/RatingCalculatorTest.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/RatingCalculatorTest.java new file mode 100644 index 000000000..816fe9b76 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/RatingCalculatorTest.java @@ -0,0 +1,37 @@ +package my.bookshop; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.math.BigDecimal; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +public class RatingCalculatorTest { + + /* + * Holder class for a book rating calculation test case. + */ + private class RatingTestFixture { + Stream ratings; + double expectedAvg; + + RatingTestFixture(Stream ratings, double expectedAvg) { + this.ratings = ratings; + this.expectedAvg = expectedAvg; + } + } + + @Test + public void testGetAvgRating() { + RatingTestFixture f1 = new RatingTestFixture(Stream.of(1.0, 2.0, 3.0, 4.0, 5.0), 3.0); + RatingTestFixture f2 = new RatingTestFixture(Stream.of(1.3, 2.4, 3.5, 4.9, 5.1), 3.4); + RatingTestFixture f3 = new RatingTestFixture(Stream.of(2.1, 4.0, 2.7, 3.8, 4.9), 3.5); + + Stream.of(f1, f2, f3).forEach(f -> { + BigDecimal avgRating = RatingCalculator.getAvgRating(f.ratings); + assertEquals(f.expectedAvg, avgRating.doubleValue()); + }); + } + +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/handlers/CatalogServiceHandlerTest.java b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/handlers/CatalogServiceHandlerTest.java new file mode 100644 index 000000000..5e97c5557 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/java/my/bookshop/handlers/CatalogServiceHandlerTest.java @@ -0,0 +1,30 @@ +package my.bookshop.handlers; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +import com.sap.cds.services.request.FeatureTogglesInfo; + +import cds.gen.catalogservice.Books; + +public class CatalogServiceHandlerTest { + + @Test + public void testDiscountHandler() { + Books book1 = Books.create(); + book1.setTitle("Book 1"); + book1.setStock(10); + Books book2 = Books.create(); + book2.setTitle("Book 2"); + book2.setStock(200); + + CatalogServiceHandler handler = new CatalogServiceHandler(null, null, null, FeatureTogglesInfo.create(), null, null); + handler.discountBooks(Stream.of(book1, book2)); + + assertEquals("Book 1", book1.getTitle(), "Book 1 was discounted"); + assertEquals("Book 2 -- 11% discount", book2.getTitle(), "Book 2 was not discounted"); + } +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/resources/META-INF/native-image/native-image.properties b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/resources/META-INF/native-image/native-image.properties new file mode 100644 index 000000000..e799b212f --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/resources/META-INF/native-image/native-image.properties @@ -0,0 +1 @@ +Args = --initialize-at-build-time=com.fasterxml.aalto.in.ReaderConfig,com.fasterxml.aalto.impl.CommonConfig diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/resources/META-INF/native-image/reflect-config.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/resources/META-INF/native-image/reflect-config.json new file mode 100644 index 000000000..fc793bf32 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/src/test/resources/META-INF/native-image/reflect-config.json @@ -0,0 +1,6 @@ +[ +{ + "name": "org.hamcrest.TypeSafeMatcher", + "queryAllDeclaredMethods": true +} +] diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/user-service.cds b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/user-service.cds new file mode 100644 index 000000000..080957ac0 --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/srv/user-service.cds @@ -0,0 +1,10 @@ +using {my.bookshop as my} from '../db/books'; + +service UserService @(requires: [ + 'admin', + 'system-user' +]) { + @odata.draft.enabled + entity Notebooks as projection on my.Notebooks; + entity Writers as projection on my.Writers; +} \ No newline at end of file diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/xs-security-mt.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/xs-security-mt.json new file mode 100644 index 000000000..ca82f740b --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/xs-security-mt.json @@ -0,0 +1,37 @@ +{ + "scopes": [ + { + "name": "$XSAPPNAME.admin", + "description": "admin" + }, + { + "name": "$XSAPPNAME.mtcallback", + "description": "Multi Tenancy Callback Access", + "grant-as-authority-to-apps": [ + "$XSAPPNAME(application,sap-provisioning,tenant-onboarding)" + ] + }, + { + "name": "$XSAPPNAME.mtdeployment", + "description": "Scope to trigger a re-deployment of the database artifacts" + }, + { + "name": "$XSAPPNAME.cds.ExtensionDeveloper", + "description": "Extend CAP applications via extension projects" + } + ], + "authorities-inheritance": false, + "authorities": [ + "$XSAPPNAME.mtdeployment" + ], + + "role-templates": [ + { + "name": "admin", + "description": "generated", + "scope-references": [ + "$XSAPPNAME.admin" + ] + } + ] +} diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/xs-security.json b/app/multi-tenant/personal-space/cloud-cap-samples-java/xs-security.json new file mode 100644 index 000000000..2d932db2b --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/xs-security.json @@ -0,0 +1,18 @@ +{ + "scopes": [ + { + "name": "$XSAPPNAME.admin", + "description": "admin" + } + ], + "role-templates": [ + { + "name": "admin", + "description": "generated", + "scope-references": [ + "$XSAPPNAME.admin" + ] + } + + ] +} diff --git a/app/single-tenant/central-space/attachments-demo-app.capnb b/app/single-tenant/central-space/attachments-demo-app.capnb new file mode 100644 index 000000000..13a6377c4 --- /dev/null +++ b/app/single-tenant/central-space/attachments-demo-app.capnb @@ -0,0 +1,244 @@ +[ + { + "kind": 1, + "language": "markdown", + "value": "# CDS SDM CAP Notebook\n\nThis CAP notebook creates a CAP Java demoapp with sample data and enhances the app with the CAP feature for attachments.\nAll needed enhancements are done. \nFor more information check the project [README](../README.md). ", + "outputs": [] + }, + { + "kind": 1, + "language": "markdown", + "value": "## Add the App with Sample Data\n`cds init` is used to create a basic CAP Java app with sample data.", + "outputs": [] + }, + { + "kind": 2, + "language": "shell", + "value": "cds init demoapp --add java,sample\n", + "outputs": [ + { + "mime": "text/plain", + "value": "Creating new CAP project" + } + ] + }, + { + "kind": 2, + "language": "shell", + "value": "cd demoapp", + "outputs": [ + { + "mime": "text/plain", + "value": "\n" + } + ] + }, + { + "kind": 1, + "language": "markdown", + "value": "## Add Enhancements for the Datamodel\nThe `books` entity will be enhanced with the `attachments` composition.\n\nTo be able to use the `sdm` datamodel a `pom.xml` needs to be added with the maven dependency for the feature.\nThe version for the dependency is taken from the file `version.txt`. \nThis file will be updated if a new version is created in the repository.\n\nOnce the `pom.xml` is available and the version is set a `mvn clean verify` is executed.\nWith the the `resolve` goal of the `cds-maven-plugin` is executed which copies the `cds`-files from the feature in the `target` folder of the `db` module.\n\nOnce available in the `target` folder it will be found and can be used in the data models.", + "outputs": [] + }, + { + "kind": 2, + "language": "shell", + "value": "%%writefile \"db/attachment-extension.cds\"\nusing {sap.capire.bookshop.Books} from './schema';\nusing {sap.attachments.Attachments} from`com.sap.cds/sdm`;\n\nextend entity Books with {\n attachments : Composition of many Attachments;\n}\n\nentity Statuses @cds.autoexpose @readonly {\n key code : StatusCode;\n text : localized String(255);\n}\n\nextend Attachments with {\n statusText : Association to Statuses on statusText.code = $self.status;\n}\n\nannotate Books.attachments with {\n status @(\n Common.Text: {\n $value: ![statusText.text],\n ![@UI.TextArrangement]: #TextOnly\n },\n ValueList: {entity:'Statuses'},\n sap.value.list: 'fixed-values'\n );\n}\n", + "outputs": [ + { + "mime": "text/html", + "value": "Wrote cell content to file demoapp/db/attachment-extension.cds.\n" + } + ] + }, + { + "kind": 2, + "language": "shell", + "value": "", + "outputs": [ + { + "mime": "text/html", + "value": "Wrote cell content to file demoapp/db/data/Statuses.csv.\n" + } + ] + }, + { + "kind": 2, + "language": "shell", + "value": "", + "outputs": [ + { + "mime": "text/html", + "value": "Wrote cell content to file demoapp/db/data/Statuses_texts.csv.\n" + } + ] + }, + { + "kind": 2, + "language": "shell", + "value": "%%writefile \"db/pom.xml\"\n\n\n\t4.0.0\n\t\n\t\tdemoapp-parent\n\t\tcustomer\n\t\t${revision}\n\t\n\n\tdb\n\n \n \n \n com.sap.cds\n sdm\n 1.0.0\n \n \n\t\n\t\n\t\t\n\t\t\t\n\t\t\t\tcom.sap.cds\n\t\t\t\tcds-maven-plugin\n\t\t\t\t${cds.services.version}\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\tcds.clean\n\t\t\t\t\t\t\n\t\t\t\t\t\t\tclean\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\tcds.resolve\n\t\t\t\t\t\t\n\t\t\t\t\t\t\tresolve\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\n\t\n\n", + "outputs": [ + { + "mime": "text/html", + "value": "Wrote cell content to file demoapp/db/pom.xml.\n" + } + ] + }, + { + "kind": 2, + "language": "shell", + "value": "cd db", + "outputs": [ + { + "mime": "text/plain", + "value": "\n" + } + ] + }, + { + "kind": 2, + "language": "java", + "value": "Path versionPath = Paths.get(\"../../version.txt\");\nString version;\nif (Files.exists(versionPath)){\n version = Files.readString(versionPath);\n System.out.println(\"Using version from 'version.txt': \" + version);\n}else{\n version = \"1.0.2\";\n System.out.println(\"Using hard coded version: \" + version);\n}\nPath pomPath = Paths.get(\"pom.xml\");\nStream lines = Files.lines(pomPath);\nList replaced = lines.map(line -> line.replaceAll(\"attachment_version\", version)).collect(Collectors.toList());\nFiles.write(pomPath, replaced);\nlines.close();", + "outputs": [ + { + "mime": "text/plain", + "value": "Using version from 'version.txt': 1.0.2\n\n\n" + } + ] + }, + { + "kind": 2, + "language": "shell", + "value": "mvn clean compile", + "outputs": [ + { + "mime": "text/plain", + "value": "" + } + ] + }, + { + "kind": 1, + "language": "markdown", + "value": "## Service Changes\n\nThe service module `srv` of the demo project needs to be updated with the maven dependency for `sdm`.\nThis dependency has included the logic to correctly handle attachments and call the `AtacchmentService`.\n\nAlso here, the version is taken from the `version.txt` which is updated in case a new version in the repository is created.", + "outputs": [] + }, + { + "kind": 2, + "language": "shell", + "value": "cd ../srv", + "outputs": [ + { + "mime": "text/plain", + "value": "\n" + } + ] + }, + { + "kind": 1, + "language": "markdown", + "value": "add the following dependency to the `srv/pom.xml`:\n```\n\n com.sap.cds\n sdm\n 1.0.0-SNAPSHOT\n\n``` ", + "outputs": [] + }, + { + "kind": 2, + "language": "java", + "value": "\nPath versionPath = Paths.get(\"../../version.txt\");\nString version;\nif (Files.exists(versionPath)){\n version = Files.readString(versionPath);\n System.out.println(\"Using version from 'version.txt': \" + version);\n}else{\n version = \"1.0.2\";\n System.out.println(\"Using hard coded version: \" + version);\n}\n\nString filePath = \"pom.xml\";\ntry {\n String pom = Files.readString(Path.of(filePath));\n String searchString = \"\";\n Pattern pattern = Pattern.compile(searchString);\n Matcher matcher = pattern.matcher(pom);\n\n if (matcher.find()) {\n System.out.println(\"String found at position: \" + matcher.start());\n } else {\n System.out.println(\"String not found\");\n }\n\n String newDependency = \"\\n\\n \\n com.sap.cds\\n sdm\\n \" + version + \"\\n \\n\\n\";\n int insertPos = matcher.end();\n pom = pom.substring(0, insertPos) + newDependency + pom.substring(insertPos);\n\n Files.writeString(Path.of(filePath), pom);\n\n} catch (IOException e) {\n e.printStackTrace();\n}", + "outputs": [ + { + "mime": "text/plain", + "value": "Using version from 'version.txt': 1.0.2\n\nString found at position: 540\n\n" + } + ] + }, + { + "kind": 2, + "language": "shell", + "value": "cd ..", + "outputs": [ + { + "mime": "text/plain", + "value": "\n" + } + ] + }, + { + "kind": 1, + "language": "markdown", + "value": "## UI Enhancements\n", + "outputs": [] + }, + { + "kind": 1, + "language": "markdown", + "value": "### UI Facet\n\nA UI facet is added for the attachments in the `AdminService`. Because the facet is only added in this service, only this services shows the attachments on the UI.\n\nThe following facet is added:\n\n```\n{\n $Type : 'UI.ReferenceFacet',\n ID : 'AttachmentsFacet',\n Label : '{i18n>attachments}',\n Target: 'attachments/@UI.LineItem'\\n \n}\n```", + "outputs": [] + }, + { + "kind": 2, + "language": "java", + "value": "String filePath = \"app/admin-books/fiori-service.cds\";\n\ntry {\n String cds = Files.readString(Path.of(filePath));\n String searchString = \"Target:\\\\s*'@UI\\\\.FieldGroup#Details'\\\\s*},\";\n Pattern pattern = Pattern.compile(searchString);\n Matcher matcher = pattern.matcher(cds);\n\n if (matcher.find()) {\n System.out.println(\"String found at position: \" + matcher.start());\n } else {\n System.out.println(\"String not found\");\n }\n\n String newFacet = \"\\n {\\n $Type : 'UI.ReferenceFacet',\\n ID : 'AttachmentsFacet',\\n Label : '{i18n>attachments}',\\n Target: 'attachments/@UI.LineItem'\\n },\";\n int insertPos = matcher.end();\n cds = cds.substring(0, insertPos) + newFacet + cds.substring(insertPos);\n\n Files.writeString(Path.of(filePath), cds);\n\n} catch (IOException e) {\n e.printStackTrace();\n}", + "outputs": [ + { + "mime": "text/plain", + "value": "String found at position: 546\n\n" + } + ] + }, + { + "kind": 1, + "language": "markdown", + "value": "### Texts\n\nThe i18n property file is enhanced with the texts for the attachments to show correct texts on the UI.", + "outputs": [] + }, + { + "kind": 2, + "language": "shell", + "value": "cd app/_i18n", + "outputs": [ + { + "mime": "text/plain", + "value": "\n" + } + ] + }, + { + "kind": 2, + "language": "java", + "value": "String filePath = \"i18n.properties\";\n\nList properties = new ArrayList<>();\nproperties.add(\"\\n\");\nproperties.add(\"#Attachment properties\\n\");\nproperties.add(\"attachment_content = Content\\n\");\nproperties.add(\"attachment_mimeType = Mime Type\\n\");\nproperties.add(\"attachment_fileName = File Name\\n\");\nproperties.add(\"attachment_status = Status\\n\");\nproperties.add(\"attachment_note = Notes\\n\");\nproperties.add(\"attachment = Attachment\\n\");\nproperties.add(\"attachments = Attachments\");\n\nfor (String property: properties){\n try {\n Files.write(Paths.get(filePath), property.getBytes(), StandardOpenOption.APPEND);\n } catch (IOException e) {\n e.printStackTrace();\n }\n}\n", + "outputs": [ + { + "mime": "text/plain", + "value": "\n" + } + ] + }, + { + "kind": 1, + "language": "markdown", + "value": "## Build the Service\n\nRun `mvn clean compile` on the service to compile the models with all changes.", + "outputs": [] + }, + { + "kind": 2, + "language": "shell", + "value": "cd ../../srv\nmvn clean compile", + "outputs": [ + { + "mime": "text/plain", + "value": "" + } + ] + }, + { + "kind": 1, + "language": "markdown", + "value": "## Start the Service\n\n\nThe service can now be started with the following command in the `srv` module:\n\n```\nmvn cds:watch\n```\n\nAfter the service is startet the UI can be opened with:\n\n[http://localhost:8080](http://localhost:8080)\n\nNavigate to the index.html of the webapp and use user `admin` with password `admin`. \n\nUsing the tile `Manage Books` the attachments can be used in the detail area of the books.\n\nUsing the tile `Browse Books` no attachments are shown.", + "outputs": [] + }, + { + "kind": 1, + "language": "markdown", + "value": "", + "outputs": [] + } +] \ No newline at end of file diff --git a/app/single-tenant/central-space/demoapp/.cdsrc.json b/app/single-tenant/central-space/demoapp/.cdsrc.json new file mode 100644 index 000000000..169ddb72c --- /dev/null +++ b/app/single-tenant/central-space/demoapp/.cdsrc.json @@ -0,0 +1,5 @@ +{ + "sql": { + "native_hana_associations" : false + } +} diff --git a/app/single-tenant/central-space/demoapp/.gitignore b/app/single-tenant/central-space/demoapp/.gitignore new file mode 100644 index 000000000..c161f228e --- /dev/null +++ b/app/single-tenant/central-space/demoapp/.gitignore @@ -0,0 +1,31 @@ +**/gen/ +**/edmx/ +*.db +*.sqlite +*.sqlite-wal +*.sqlite-shm +schema*.sql +default-env.json + +**/bin/ +**/target/ +.flattened-pom.xml +.classpath +.project +.settings + +**/node/ +**/node_modules/ + +**/.mta/ +*.mtar + +*.log* +gc_history* +hs_err* +*.tgz +*.iml + +.vscode +.idea +.reloadtrigger diff --git a/app/single-tenant/central-space/demoapp/app/_i18n/i18n.properties b/app/single-tenant/central-space/demoapp/app/_i18n/i18n.properties new file mode 100644 index 000000000..6bca9e0ec --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/_i18n/i18n.properties @@ -0,0 +1,66 @@ +Books = Books +Book = Book +ID = ID +Title = Title +Author = Author +Authors = Authors +AuthorID = Author ID +AuthorName = Author Name +Name = Name +Age = Age +Stock = Stock +Order = Order +Orders = Orders +Price = Price +Genre = Genre +#Attachment properties +attachment_content = Attachment +attachment_mimeType = Mime Type +attachment_fileName = Filename +attachment_status = Status +attachment_note = Note +attachment = Attachment +attachments = Attachments +reference = Reference +references = References +uploadStatus = Upload Status +type=Type + +#XFLD,50: Label for a section +Chapters=Chapters + +#XFLD,120: Label for entity +Chapter=Chapter + +#XFLD,120: Label for a field +ChapterTitle=Chapter Title + +#XFLD,120: Label for a field +ChapterType=Chapter Type + +#XFLD,50: Label for a section +Pages=Pages + +#XFLD,120: Label for entity +Page=Page + +#XFLD,120: Label for a field +PageTitle=Page Title + +#XFLD,120: Label for a field +PageType=Page Type + +#XFLD,50: Label for a section +Footnotes=Footnotes + +#XFLD,120: Label for a field +Description=Description + +#XFLD,120: Label for a field +URL=URL + +#XFLD,50: Label for a section +GeneralInformation=General Information + +#XFLD,50: Label for a section +Attachments=Attachments diff --git a/app/single-tenant/central-space/demoapp/app/_i18n/i18n_de.properties b/app/single-tenant/central-space/demoapp/app/_i18n/i18n_de.properties new file mode 100644 index 000000000..7046fa3e8 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/_i18n/i18n_de.properties @@ -0,0 +1,51 @@ +Books = Bücher +Book = Buch +ID = ID +Title = Titel +Author = Autor +Authors = Autoren +AuthorID = ID des Autors +AuthorName = Name des Autors +Name = Name +Age = Alter +Stock = Bestand +Order = Bestellung +Orders = Bestellungen +Price = Preis +Genre = Genre + +#XFLD,50: Label for a section +Chapters=Kapitel + +#XFLD,120: Label for entity +Chapter=Kapitel + +#XFLD,120: Label for a field +ChapterTitle=Kapitel Titel + +#XFLD,120: Label for a field +ChapterType=Kapitel Typ + +#XFLD,50: Label for a section +Pages=Seiten + +#XFLD,120: Label for entity +Page=Seite + +#XFLD,120: Label for a field +PageTitle=Seiten Titel + +#XFLD,120: Label for a field +PageType=Seiten Typ + +#XFLD,50: Label for a section +Footnotes=Fußnoten + +#XFLD,120: Label for a field +Description=Beschreibung + +#XFLD,120: Label for a field +URL=URL + +#XFLD,50: Label for a section +GeneralInformation=Allgemeine Informationen \ No newline at end of file diff --git a/app/single-tenant/central-space/demoapp/app/admin-books/fiori-service.cds b/app/single-tenant/central-space/demoapp/app/admin-books/fiori-service.cds new file mode 100644 index 000000000..146ea4cfd --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/admin-books/fiori-service.cds @@ -0,0 +1,375 @@ +using {AdminService} from '../../srv/admin-service.cds'; + +//////////////////////////////////////////////////////////////////////////// +// +// 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', + ID : 'AttachmentsFacet', + Label : '{i18n>attachments}', + Target: 'attachments/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'ReferencesFacet', + Label : '{i18n>references}', + Target: 'references/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'FootnotesFacet', + Label : 'Footnotes', + Target: 'footnotes/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>Admin}', + Target: '@UI.FieldGroup#Admin' + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>Chapters}', + ID : 'i18nChapters', + Target : 'cHapters/@UI.LineItem#i18nChapters', + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>Pages}', + ID : 'i18nPages', + Target : 'pages/@UI.LineItem#i18nPages', + }, + ], + 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} + ]} +}); + +////////// + +// Chapters annotations +annotate AdminService.Chapters with @title : '{i18n>Chapter}'; + +annotate AdminService.Books.chapters with @( + title : '{i18n>Chapters}' +); + +annotate AdminService.Chapters with @( + UI.LineItem : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>ChapterTitle}', + }, + { + $Type : 'UI.DataField', + Value : chapterType, + Label : '{i18n>ChapterType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + ], + UI.LineItem #i18nChapters : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>ChapterTitle}', + }, + { + $Type : 'UI.DataField', + Value : chapterType, + Label : '{i18n>ChapterType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + ] +); + +annotate AdminService.Chapters with @( + UI.HeaderInfo : { + Title : { + $Type : 'UI.DataField', + Value : title, + }, + TypeName : '{i18n>Chapter}', + TypeNamePlural : '{i18n>Chapters}', + Description : { + $Type : 'UI.DataField', + Value : description, + }, + } +); + +annotate AdminService.Chapters with @( + UI.FieldGroup #GeneratedGroup1 : { + $Type : 'UI.FieldGroupType', + Data : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>ChapterTitle}', + }, + { + $Type : 'UI.DataField', + Value : chapterType, + Label : '{i18n>ChapterType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + { + $Type : 'UI.DataField', + Value : url, + Label : '{i18n>URL}', + }, + ], + }, + UI.Facets : [ + { + $Type : 'UI.ReferenceFacet', + ID : 'GeneratedFacet1', + Label : '{i18n>GeneralInformation}', + Target : '@UI.FieldGroup#GeneratedGroup1', + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'AttachmentsFacet', + Label : '{i18n>attachments}', + Target : 'attachments/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'ReferencesFacet', + Label : '{i18n>references}', + Target : 'references/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'FootnotesFacet', + Label : '{i18n>Footnotes}', + Target : 'footnotes/@UI.LineItem' + } + ] +); + +////////// + +// Pages annotations +annotate AdminService.Pages with @title : '{i18n>Page}'; + +annotate AdminService.Books.pages with @( + title : '{i18n>Pages}' +); + +annotate AdminService.Pages with @( + UI.LineItem : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>PageTitle}', + }, + { + $Type : 'UI.DataField', + Value : pageType, + Label : '{i18n>PageType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + ], + UI.LineItem #i18nPages : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>PageTitle}', + }, + { + $Type : 'UI.DataField', + Value : pageType, + Label : '{i18n>PageType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + ] +); + +annotate AdminService.Pages with @( + UI.HeaderInfo : { + Title : { + $Type : 'UI.DataField', + Value : title, + }, + TypeName : '{i18n>Page}', + TypeNamePlural : '{i18n>Pages}', + Description : { + $Type : 'UI.DataField', + Value : description, + }, + } +); + +annotate AdminService.Pages with @( + UI.FieldGroup #GeneratedGroup1 : { + $Type : 'UI.FieldGroupType', + Data : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>PageTitle}', + }, + { + $Type : 'UI.DataField', + Value : pageType, + Label : '{i18n>PageType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + { + $Type : 'UI.DataField', + Value : url, + Label : '{i18n>URL}', + }, + ], + }, + UI.Facets : [ + { + $Type : 'UI.ReferenceFacet', + ID : 'GeneratedFacet1', + Label : '{i18n>GeneralInformation}', + Target : '@UI.FieldGroup#GeneratedGroup1', + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'AttachmentsFacet', + Label : '{i18n>attachments}', + Target : 'attachments/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'ReferencesFacet', + Label : '{i18n>references}', + Target : 'references/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'FootnotesFacet', + Label : '{i18n>Footnotes}', + Target : 'footnotes/@UI.LineItem' + } + ] +); + + +//////////////////////////////////////////////////////////// +// +// 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' + }, + ] +}); + +annotate AdminService.Books.texts with { + ID @UI.Hidden; + ID_texts @UI.Hidden; +}; + +// Add Value Help for Locales +annotate AdminService.Books.texts { + locale @( + ValueList.entity: 'Languages', + Common.ValueListWithFixedValues, //show as drop down, not a dialog + ) +}; + +// In addition we need to expose Languages through AdminService as a target for ValueList +using {sap} from '@sap/cds/common'; + +extend service AdminService { + @readonly + entity Languages as projection on sap.common.Languages; +} + +// Workaround for Fiori popup for asking user to enter a new UUID on Create +annotate AdminService.Books with { + ID @Core.Computed; +} + +// Show Genre as drop down, not a dialog +annotate AdminService.Books with { + genre @Common.ValueListWithFixedValues; +} + +annotate AdminService.Books.attachments with { + customProperty1 @Common.ValueListWithFixedValues; +} diff --git a/app/single-tenant/central-space/demoapp/app/admin-books/package.json b/app/single-tenant/central-space/demoapp/app/admin-books/package.json new file mode 100644 index 000000000..5acd4af83 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/admin-books/package.json @@ -0,0 +1,13 @@ +{ + "name": "admin-books", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" + } + \ No newline at end of file diff --git a/app/single-tenant/central-space/demoapp/app/admin-books/webapp/Component.js b/app/single-tenant/central-space/demoapp/app/admin-books/webapp/Component.js new file mode 100644 index 000000000..e98677ee9 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/admin-books/webapp/Component.js @@ -0,0 +1,8 @@ +sap.ui.define(["sap/fe/core/AppComponent"], function (AppComponent) { + "use strict"; + return AppComponent.extend("books.Component", { + metadata: { manifest: "json" } + }); +}); + +/* eslint no-undef:0 */ diff --git a/app/single-tenant/central-space/demoapp/app/admin-books/webapp/controller/custom.controller.js b/app/single-tenant/central-space/demoapp/app/admin-books/webapp/controller/custom.controller.js new file mode 100644 index 000000000..1488f9189 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/admin-books/webapp/controller/custom.controller.js @@ -0,0 +1,141 @@ +sap.ui.define( + [ + "sap/ui/core/mvc/ControllerExtension", + "sap/m/library", + "sap/ui/core/format/DateFormat" + ], + function (ControllerExtension, library, DateFormat) { + "use strict"; + const ChangeCategoryEnum = { + created: "Created", + updated: "Changed" + // Add more mappings as needed + }; + + return ControllerExtension.extend("books.controller.custom", { + isDownloadEnabled: function(oBindingContext, aSelectedContexts) { + if (!aSelectedContexts || aSelectedContexts.length === 0) { + return false; + } + return !aSelectedContexts.some(function(oContext) { + return oContext.getProperty("mimeType") === "application/internet-shortcut"; + }); + }, + onRowPress: function(oContext) { + this.base.editFlow + .invokeAction("AdminService.openAttachment", { + contexts: oContext.getParameter("bindingContext") + }) + .then(function (res) { + let odataurl = ""; + if(res.getObject().value == "None") { + const lastSlashIndex = res.oModel.getServiceUrl().lastIndexOf('/'); + let str = res.oModel.getServiceUrl(); + if (lastSlashIndex !== -1) { + str = str.substring(0, lastSlashIndex) + str.substring(lastSlashIndex + 1); + } + odataurl = str+res.oBinding.oContext.sPath+"/content"; + } else { + odataurl = res.getObject().value; + } + library.URLHelper.redirect(odataurl, true); + + }); + }, + onChangelogPress: function(oContext, aSelectedContexts) { + var that =this; + this.base.editFlow + .invokeAction("AdminService.changelog", { + contexts: aSelectedContexts + }) + .then(function (res) { + console.log("Result",res[0].value.getObject().value); + that.updateChangeLogInPropertiesModel(res[0].value.getObject().value); + }); + }, + updateChangeLogInPropertiesModel: function (oChangeLogsForObjectResponse) { + const aChangeLogs = []; + const fileName = JSON.parse(oChangeLogsForObjectResponse).filename; + console.log("Filename: ", fileName); + const aChangeLogsObject = JSON.parse(oChangeLogsForObjectResponse)["changeLogs"]; + console.log("ChangeLogsObject:\n", aChangeLogsObject); + // Take latest changes at the top + for (let idx = aChangeLogsObject.length - 1; idx >= 0; idx--) { + const oChangeLogEntry = aChangeLogsObject[idx]; + const sLastModifiedBy = oChangeLogEntry["user"]; + const sChangeType = oChangeLogEntry["operation"]; + const sChangeTime = oChangeLogEntry["time"]; + let dateTimeFormat = DateFormat.getDateTimeInstance(sap.ui.getCore().getConfiguration().getLocale()); + let changedDate = new Date(sChangeTime); + let changedTime = changedDate?dateTimeFormat.format(new Date(changedDate)) : "" ; + const oChangeLog = { + changedOn: changedTime, + changedBy: sLastModifiedBy, + changeType: ChangeCategoryEnum[sChangeType] + }; + aChangeLogs.push(oChangeLog); + console.log("ChangeLog:\n", oChangeLog); + } + + this.logFragment= this.base.getExtensionAPI().loadFragment({ + name: "books.fragments.changelog", + controller: this + }); + var that = this; + this.logFragment.then(function (dialog) { + if(dialog){ + dialog.attachEventOnce("afterClose", function () { + dialog.destroy(); + }); + var oModel = new sap.ui.model.json.JSONModel(); + oModel.setSizeLimit(100000); + oModel.setData(aChangeLogs); + that.getView().setModel(oModel, "changelog"); + dialog.setTitle(fileName); + dialog.open() + } + }); + }, + close: function (closeBtn) { + closeBtn.getSource().getParent().close(); + }, + onDownloadPress: function(oContext, aSelectedContexts) { + var sIds = aSelectedContexts.map(function(oCtx) { + return oCtx.getObject().ID; + }).join(","); + this.base.editFlow + .invokeAction("AdminService.downloadSelectedAttachments", { + contexts: aSelectedContexts[0], + parameterValues: [{ name: "ids", value: sIds }], + skipParameterDialog: true + }) + .then(function (res) { + var sJsonResponse = res.getObject().value; + var aEntries = JSON.parse(sJsonResponse); + aEntries.forEach(function (oEntry) { + if (oEntry.status === "success") { + if (oEntry.linkUrl) { + window.open(oEntry.linkUrl, "_blank"); + } else if (oEntry.content) { + var byteString = atob(oEntry.content); + var aBytes = new Uint8Array(byteString.length); + for (var i = 0; i < byteString.length; i++) { + aBytes[i] = byteString.charCodeAt(i); + } + var oBlob = new Blob([aBytes], { type: oEntry.mimeType || "application/octet-stream" }); + var sUrl = URL.createObjectURL(oBlob); + var oLink = document.createElement("a"); + oLink.href = sUrl; + oLink.download = oEntry.fileName || "download"; + document.body.appendChild(oLink); + oLink.click(); + document.body.removeChild(oLink); + URL.revokeObjectURL(sUrl); + } + } + }); + }); + } + }); + } +); \ No newline at end of file diff --git a/app/single-tenant/central-space/demoapp/app/admin-books/webapp/fragments/changelog.fragment.xml b/app/single-tenant/central-space/demoapp/app/admin-books/webapp/fragments/changelog.fragment.xml new file mode 100644 index 000000000..1a1462526 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/admin-books/webapp/fragments/changelog.fragment.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+ + +
+
\ No newline at end of file diff --git a/app/single-tenant/central-space/demoapp/app/admin-books/webapp/i18n/i18n.properties b/app/single-tenant/central-space/demoapp/app/admin-books/webapp/i18n/i18n.properties new file mode 100644 index 000000000..9a23ee40a --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/admin-books/webapp/i18n/i18n.properties @@ -0,0 +1,3 @@ +appTitle=Manage Books +appSubTitle=Manage bookshop inventory +appDescription=Manage your bookshop inventory with ease. diff --git a/app/single-tenant/central-space/demoapp/app/admin-books/webapp/i18n/i18n_de.properties b/app/single-tenant/central-space/demoapp/app/admin-books/webapp/i18n/i18n_de.properties new file mode 100644 index 000000000..01d56a22c --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/admin-books/webapp/i18n/i18n_de.properties @@ -0,0 +1,3 @@ +appTitle=Bücher verwalten +appSubTitle=Verwalten Sie den Bestand der Buchhandlungen +appDescription=Verwalten Sie den Bestand Ihrer Buchhandlung ganz einfach. diff --git a/app/single-tenant/central-space/demoapp/app/admin-books/webapp/manifest.json b/app/single-tenant/central-space/demoapp/app/admin-books/webapp/manifest.json new file mode 100644 index 000000000..8eb3b6df1 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/admin-books/webapp/manifest.json @@ -0,0 +1,477 @@ +{ + "_version": "1.49.0", + "sap.app": { + "applicationVersion": { + "version": "1.0.0" + }, + "id": "demoapp.admin-books", + "type": "application", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "i18n": "i18n/i18n.properties", + "dataSources": { + "AdminService": { + "uri": "/odata/v4/AdminService/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + }, + "crossNavigation": { + "inbounds": { + "Books-manage": { + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "semanticObject": "Books", + "action": "manage" + } + } + } + }, + "sap.ui": { + "technology": "UI5", + "fullWidth": false, + "deviceTypes": { + "desktop": true, + "tablet": true, + "phone": true + } + }, + "sap.ui5": { + "dependencies": { + "minUI5Version": "1.115.1", + "libs": { + "sap.fe.templates": {} + } + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "i18n/i18n.properties" + }, + "": { + "dataSource": "AdminService", + "settings": { + "synchronizationMode": "None", + "operationMode": "Server", + "autoExpandSelect": true, + "earlyRequests": true, + "groupProperties": { + "default": { + "submit": "Auto" + } + } + } + } + }, + "routing": { + "routes": [ + { + "pattern": ":?query:", + "name": "BooksList", + "target": "BooksList" + }, + { + "pattern": "Books({key}):?query:", + "name": "BooksDetails", + "target": "BooksDetails" + }, + { + "pattern": "Books({key}/author({key2}):?query:", + "name": "AuthorsDetails", + "target": "AuthorsDetails" + }, + { + "pattern": "Books({key})/cHapters({key2}):?query:", + "name": "chaptersObjectPage", + "target": "ChaptersObjectPage" + }, + { + "pattern": "Books({key})/pages({key2}):?query:", + "name": "pagesObjectPage", + "target": "PagesObjectPage" + } + ], + "targets": { + "BooksList": { + "type": "Component", + "id": "BooksList", + "name": "sap.fe.templates.ListReport", + "options": { + "settings": { + "entitySet": "Books", + "initialLoad": true, + "navigation": { + "Books": { + "detail": { + "route": "BooksDetails" + } + } + } + } + } + }, + "BooksDetails": { + "type": "Component", + "id": "BooksDetailsList", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings": { + "entitySet": "Books", + "navigation": { + "Chapters": { + "detail": { + "route": "ChaptersObjectPage" + } + }, + "Pages": { + "detail": { + "route": "PagesObjectPage" + } + } + }, + "controlConfiguration": { + "attachments/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.books.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.books.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.books.controller.custom.isDownloadEnabled", + "press": ".extension.books.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "references/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.books.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.books.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.books.controller.custom.isDownloadEnabled", + "press": ".extension.books.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "footnotes/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.books.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.books.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.books.controller.custom.isDownloadEnabled", + "press": ".extension.books.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + } + } + } + } + }, + "ChaptersObjectPage": { + "type": "Component", + "id": "ChaptersObjectPage", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings": { + "editableHeaderContent": false, + "entitySet": "Chapters", + "controlConfiguration": { + "attachments/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.books.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.books.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.books.controller.custom.isDownloadEnabled", + "press": ".extension.books.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "references/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.books.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.books.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.books.controller.custom.isDownloadEnabled", + "press": ".extension.books.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "footnotes/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.books.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.books.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.books.controller.custom.isDownloadEnabled", + "press": ".extension.books.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + } + } + } + } + }, + "PagesObjectPage": { + "type": "Component", + "id": "PagesObjectPage", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings": { + "editableHeaderContent": false, + "entitySet": "Pages", + "navigation": {}, + "controlConfiguration": { + "attachments/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.books.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.books.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.books.controller.custom.isDownloadEnabled", + "press": ".extension.books.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "references/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.books.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.books.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.books.controller.custom.isDownloadEnabled", + "press": ".extension.books.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "footnotes/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.books.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.books.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.books.controller.custom.isDownloadEnabled", + "press": ".extension.books.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + } + } + } + } + }, + "SectionsObjectPage": { + "type": "Component", + "id": "SectionsObjectPage", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings": { + "editableHeaderContent": false, + "entitySet": "Sections", + "navigation": {} + } + } + }, + "AuthorsDetails": { + "type": "Component", + "id": "AuthorsDetailsList", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings": { + "entitySet": "Authors" + } + } + } + } + }, + "extends": { + "extensions": { + "sap.ui.controllerExtensions": { + "sap.fe.templates.ObjectPage.ObjectPageController#books::BooksDetailsList": { + "controllerName": "books.controller.custom" + }, + "sap.fe.templates.ObjectPage.ObjectPageController#books::ChaptersObjectPage": { + "controllerName": "books.controller.custom" + }, + "sap.fe.templates.ObjectPage.ObjectPageController#books::PagesObjectPage": { + "controllerName": "books.controller.custom" + } + } + } + }, + "contentDensities": { + "compact": true, + "cozy": true + } + }, + "sap.fiori": { + "registrationIds": [], + "archeType": "transactional" + } +} diff --git a/app/single-tenant/central-space/demoapp/app/appconfig/fioriSandboxConfig.json b/app/single-tenant/central-space/demoapp/app/appconfig/fioriSandboxConfig.json new file mode 100644 index 000000000..ff2ac499b --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/appconfig/fioriSandboxConfig.json @@ -0,0 +1,95 @@ +{ + "services": { + "LaunchPage": { + "adapter": { + "config": { + "catalogs": [], + "groups": [ + { + "id": "Bookshop", + "title": "Bookshop", + "isPreset": true, + "isVisible": true, + "isGroupLocked": false, + "tiles": [ + { + "id": "BrowseBooks", + "tileType": "sap.ushell.ui.tile.StaticTile", + "properties": { + "title": "Browse Books", + "targetURL": "#Books-display" + } + } + ] + }, + { + "id": "Administration", + "title": "Administration", + "isPreset": true, + "isVisible": true, + "isGroupLocked": false, + "tiles": [ + { + "id": "ManageBooks", + "tileType": "sap.ushell.ui.tile.StaticTile", + "properties": { + "title": "Manage Books", + "targetURL": "#Books-manage" + } + } + ] + } + ] + } + } + }, + "NavTargetResolution": { + "config": { + "enableClientSideTargetResolution": true + } + }, + "ClientSideTargetResolution": { + "adapter": { + "config": { + "inbounds": { + "BrowseBooks": { + "semanticObject": "Books", + "action": "display", + "title": "Browse Books", + "signature": { + "parameters": { + "Books.ID": { + "renameTo": "ID" + }, + "Authors.books.ID": { + "renameTo": "ID" + } + }, + "additionalParameters": "ignored" + }, + "resolutionResult": { + "applicationType": "SAPUI5", + "additionalInformation": "SAPUI5.Component=bookshop", + "url": "browse/webapp" + } + }, + "ManageBooks": { + "semanticObject": "Books", + "action": "manage", + "title": "Manage Books", + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "resolutionResult": { + "applicationType": "SAPUI5", + "additionalInformation": "SAPUI5.Component=books", + "url": "admin-books/webapp" + } + } + } + } + } + } + } +} diff --git a/app/single-tenant/central-space/demoapp/app/browse/fiori-service.cds b/app/single-tenant/central-space/demoapp/app/browse/fiori-service.cds new file mode 100644 index 000000000..5ae5c9d70 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/browse/fiori-service.cds @@ -0,0 +1,56 @@ +using {CatalogService} from '../../srv/cat-service.cds'; + +//////////////////////////////////////////////////////////////////////////// +// +// 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 List Page +// +annotate CatalogService.Books with @(UI: { + SelectionFields: [ + ID, + price, + currency_code + ], + LineItem : [ + { + Value: ID, + Label: '{i18n>Title}' + }, + { + Value: author, + Label: '{i18n>Author}' + }, + {Value: genre.name}, + {Value: price}, + {Value: currency.symbol}, + ] +}); diff --git a/app/single-tenant/central-space/demoapp/app/browse/webapp/Component.js b/app/single-tenant/central-space/demoapp/app/browse/webapp/Component.js new file mode 100644 index 000000000..4020679f8 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/browse/webapp/Component.js @@ -0,0 +1,7 @@ +sap.ui.define(["sap/fe/core/AppComponent"], function(AppComponent) { + "use strict"; + return AppComponent.extend("bookshop.Component", { + metadata: { manifest: "json" } + }); +}); +/* eslint no-undef:0 */ diff --git a/app/single-tenant/central-space/demoapp/app/browse/webapp/i18n/i18n.properties b/app/single-tenant/central-space/demoapp/app/browse/webapp/i18n/i18n.properties new file mode 100644 index 000000000..21436e8e4 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/browse/webapp/i18n/i18n.properties @@ -0,0 +1,3 @@ +appTitle=Browse Books +appSubTitle=Find all your favorite books +appDescription=This application lets you find the next books you want to read. diff --git a/app/single-tenant/central-space/demoapp/app/browse/webapp/i18n/i18n_de.properties b/app/single-tenant/central-space/demoapp/app/browse/webapp/i18n/i18n_de.properties new file mode 100644 index 000000000..ea86c3f29 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/browse/webapp/i18n/i18n_de.properties @@ -0,0 +1,3 @@ +appTitle=Bücher anschauen +appSubTitle=Finden sie ihre nächste Lektüre +appDescription=Finden Sie die nachsten Bücher, die Sie lesen möchten. diff --git a/app/single-tenant/central-space/demoapp/app/browse/webapp/manifest.json b/app/single-tenant/central-space/demoapp/app/browse/webapp/manifest.json new file mode 100644 index 000000000..5754f332c --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/browse/webapp/manifest.json @@ -0,0 +1,138 @@ +{ + "_version": "1.49.0", + "sap.app": { + "id": "demoapp.browse", + "applicationVersion": { + "version": "1.0.0" + }, + "type": "application", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "i18n": "i18n/i18n.properties", + "dataSources": { + "CatalogService": { + "uri": "/odata/v4/CatalogService/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + }, + "crossNavigation": { + "inbounds": { + "intent1": { + "signature": { + "parameters": { + "Books.ID": { + "renameTo": "ID" + }, + "Authors.books.ID": { + "renameTo": "ID" + } + }, + "additionalParameters": "ignored" + }, + "semanticObject": "Books", + "action": "display", + "title": "{{appTitle}}", + "subTitle": "{{appSubTitle}}", + "icon": "sap-icon://course-book", + "indicatorDataSource": { + "dataSource": "CatalogService", + "path": "Books/$count", + "refresh": 1800 + } + } + } + } + }, + "sap.ui": { + "technology": "UI5", + "fullWidth": false, + "deviceTypes": { + "desktop": true, + "tablet": true, + "phone": true + } + }, + "sap.ui5": { + "dependencies": { + "minUI5Version": "1.115.1", + "libs": { + "sap.fe.templates": {} + } + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "i18n/i18n.properties" + }, + "": { + "dataSource": "CatalogService", + "settings": { + "synchronizationMode": "None", + "operationMode": "Server", + "autoExpandSelect": true, + "earlyRequests": true, + "groupProperties": { + "default": { + "submit": "Auto" + } + } + } + } + }, + "routing": { + "routes": [ + { + "pattern": ":?query:", + "name": "BooksList", + "target": "BooksList" + }, + { + "pattern": "Books({key}):?query:", + "name": "BooksDetails", + "target": "BooksDetails" + } + ], + "targets": { + "BooksList": { + "type": "Component", + "id": "BooksList", + "name": "sap.fe.templates.ListReport", + "options": { + "settings": { + "entitySet": "Books", + "initialLoad": true, + "navigation": { + "Books": { + "detail": { + "route": "BooksDetails" + } + } + } + } + } + }, + "BooksDetails": { + "type": "Component", + "id": "BooksDetailsList", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings": { + "entitySet": "Books" + } + } + } + } + }, + "contentDensities": { + "compact": true, + "cozy": true + } + }, + "sap.fiori": { + "registrationIds": [], + "archeType": "transactional" + } +} diff --git a/app/single-tenant/central-space/demoapp/app/common.cds b/app/single-tenant/central-space/demoapp/app/common.cds new file mode 100644 index 000000000..90326595f --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/common.cds @@ -0,0 +1,1070 @@ +/* + Common Annotations shared by all apps +*/ + +using { sap.capire.bookshop as my } from '../db/schema'; +using { sap.common, sap.common.Currencies } from '@sap/cds/common'; + +//////////////////////////////////////////////////////////////////////////// +// +// Books Lists +// +annotate my.Books with @( + Common.SemanticKey: [ID], + UI: { + Identification: [{ Value: title }], + SelectionFields: [ + ID, + author_ID, + price, + currency_code + ], + LineItem: [ + { Value: ID, Label: '{i18n>Title}' }, + { Value: author.ID, Label: '{i18n>Author}' }, + { Value: genre.name }, + { Value: stock }, + { Value: price }, + { Value: currency.symbol }, + ] + } +) { + ID @Common: { + SemanticObject: 'Books', + Text: title, + TextArrangement: #TextOnly + }; + author @ValueList.entity: 'Authors'; +}; + +annotate Currencies with { + symbol @Common.Label: '{i18n>Currency}'; +} + +//////////////////////////////////////////////////////////////////////////// +// +// Books Details +// +annotate my.Books with @(UI : {HeaderInfo : { + TypeName : '{i18n>Book}', + TypeNamePlural: '{i18n>Books}', + Title : { Value: title }, + Description : { Value: author.name } +}, }); + +//////////////////////////////////////////////////////////////////////////// +// +// Attachments Details +// + +annotate my.Books.attachments with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Attachment}', + TypeNamePlural: '{i18n>Attachments}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Attachments', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + uploadStatus @(title: '{i18n>uploadStatus}', Common.Text : uploadStatusNav.name, Common.TextArrangement : #TextOnly); + type @(title: '{i18n>type}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} +annotate Attachments with @Common: {SideEffects #ContentChanged: { + SourceProperties: [content], + TargetProperties: ['status'], + TargetEntities : [Books.attachments] +}}{}; + +annotate my.Books.references with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Attachment}', + TypeNamePlural: '{i18n>Attachments}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Attachments', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + uploadStatus @(title: '{i18n>uploadStatus}', Common.Text : uploadStatusNav.name, Common.TextArrangement : #TextOnly); + type @(title: '{i18n>type}'); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Books.footnotes with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Attachment}', + TypeNamePlural: '{i18n>Attachments}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Attachments', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + uploadStatus @(title: '{i18n>uploadStatus}', Common.Text : uploadStatusNav.name, Common.TextArrangement : #TextOnly); + type @(title: '{i18n>type}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Chapters.attachments with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Attachment}', + TypeNamePlural: '{i18n>Attachments}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Attachments', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + uploadStatus @(title: '{i18n>uploadStatus}', Common.Text : uploadStatusNav.name, Common.TextArrangement : #TextOnly); + type @(title: '{i18n>type}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Chapters.references with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Reference}', + TypeNamePlural: '{i18n>References}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy References', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + uploadStatus @(title: '{i18n>uploadStatus}', Common.Text : uploadStatusNav.name, Common.TextArrangement : #TextOnly); + type @(title: '{i18n>type}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Chapters.footnotes with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Footnote}', + TypeNamePlural: '{i18n>Footnotes}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Footnotes', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + uploadStatus @(title: '{i18n>uploadStatus}', Common.Text : uploadStatusNav.name, Common.TextArrangement : #TextOnly); + type @(title: '{i18n>type}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Pages.attachments with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Attachment}', + TypeNamePlural: '{i18n>Attachments}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Attachments', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + uploadStatus @(title: '{i18n>uploadStatus}', Common.Text : uploadStatusNav.name, Common.TextArrangement : #TextOnly); + type @(title: '{i18n>type}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Pages.references with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Reference}', + TypeNamePlural: '{i18n>References}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy References', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + uploadStatus @(title: '{i18n>uploadStatus}', Common.Text : uploadStatusNav.name, Common.TextArrangement : #TextOnly); + type @(title: '{i18n>type}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Pages.footnotes with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Footnote}', + TypeNamePlural: '{i18n>Footnotes}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Footnotes', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + uploadStatus @(title: '{i18n>uploadStatus}', Common.Text : uploadStatusNav.name, Common.TextArrangement : #TextOnly); + type @(title: '{i18n>type}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +//////////////////////////////////////////////////////////////////////////// +// +// Books Elements +// +annotate my.Books with { + ID @title: '{i18n>ID}'; + 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}' @Measures.ISOCurrency: currency_code; + stock @title: '{i18n>Stock}'; + descr @title: '{i18n>Description}' @UI.MultiLineText; + image @title: '{i18n>Image}'; +} + +//////////////////////////////////////////////////////////////////////////// +// +// Genres List +// +annotate my.Genres with @( + Common.SemanticKey: [name], + UI: { + SelectionFields: [name], + LineItem: [ + { Value: name }, + { + Value: parent.name, + Label: 'Main Genre' + }, + ], + } +); + +annotate my.Genres with { + ID @Common.Text : name @Common.TextArrangement : #TextOnly; +} + +//////////////////////////////////////////////////////////////////////////// +// +// 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: [ID], + UI: { + Identification : [{ Value: name}], + SelectionFields: [ name ], + LineItem : [ + { Value: ID }, + { Value: dateOfBirth }, + { Value: dateOfDeath }, + { Value: placeOfBirth }, + { Value: placeOfDeath }, + ], + } +) { + ID @Common: { + SemanticObject: 'Authors', + Text: name, + TextArrangement: #TextOnly, + }; +}; + +//////////////////////////////////////////////////////////////////////////// +// +// 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}'; + 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' + } + ], + FieldGroup #Details: {Data : [ + { Value: name }, + { Value: symbol }, + { Value: code }, + { Value: descr } + ]} +}); \ No newline at end of file diff --git a/app/single-tenant/central-space/demoapp/app/index.html b/app/single-tenant/central-space/demoapp/app/index.html new file mode 100644 index 000000000..1b0453bef --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/index.html @@ -0,0 +1,32 @@ + + + + + + + + Bookshop + + + + + + + + + + diff --git a/app/single-tenant/central-space/demoapp/app/package.json b/app/single-tenant/central-space/demoapp/app/package.json new file mode 100644 index 000000000..fa9d34967 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/package.json @@ -0,0 +1,9 @@ +{ + "name": "approuter", + "dependencies": { + "@sap/approuter": "16.8.2" + }, + "scripts": { + "start": "node node_modules/@sap/approuter/approuter.js" + } +} diff --git a/app/single-tenant/central-space/demoapp/app/services.cds b/app/single-tenant/central-space/demoapp/app/services.cds new file mode 100644 index 000000000..87e7b310f --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/services.cds @@ -0,0 +1,6 @@ +/* + This model controls what gets served to Fiori frontends... +*/ +using from './common'; +using from './browse/fiori-service'; +using from './admin-books/fiori-service'; diff --git a/app/single-tenant/central-space/demoapp/app/xs-app.json b/app/single-tenant/central-space/demoapp/app/xs-app.json new file mode 100644 index 000000000..069ad9797 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/app/xs-app.json @@ -0,0 +1,85 @@ +{ + "welcomeFile": "/app/index.html", + "authenticationMethod": "route", + "routes": [ + { + "source": "^/odata/(.*)$", + "target": "/odata/$1", + "destination": "backend", + "authenticationType": "xsuaa", + "csrfProtection": false + }, + { + "source": "^/app/(.*)$", + "cacheControl": "no-cache, no-store, must-revalidate", + "target": "$1", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/appconfig/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/browse/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/admin-books/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/orders/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/reviews/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/notes/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/addresses/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/vue/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/api/admin/(.*)", + "authenticationType": "xsuaa", + "destination": "backend" + }, + { + "source": "^/api/browse/(.*)", + "authenticationType": "xsuaa", + "destination": "backend" + }, + { + "source": "^/api/review/(.*)", + "authenticationType": "xsuaa", + "destination": "backend" + }, + { + "source": "^/api/notes/(.*)", + "authenticationType": "xsuaa", + "destination": "backend" + }, + { + "source": "^/api/(.*)$", + "authenticationType": "none", + "destination": "backend" + } + ] +} diff --git a/app/single-tenant/central-space/demoapp/db/data/WDIRSCodeList.csv b/app/single-tenant/central-space/demoapp/db/data/WDIRSCodeList.csv new file mode 100644 index 000000000..d2bbc28bf --- /dev/null +++ b/app/single-tenant/central-space/demoapp/db/data/WDIRSCodeList.csv @@ -0,0 +1,4 @@ +code;name +A;Promotions type A +B;Promotions type B +C;Promotions type C \ No newline at end of file diff --git a/app/single-tenant/central-space/demoapp/db/data/sap.attachments-UploadScanStates.csv b/app/single-tenant/central-space/demoapp/db/data/sap.attachments-UploadScanStates.csv new file mode 100644 index 000000000..8432b60db --- /dev/null +++ b/app/single-tenant/central-space/demoapp/db/data/sap.attachments-UploadScanStates.csv @@ -0,0 +1,6 @@ +code;name;criticality +uploading;Uploading;5 +Success;Success;3 +Failed;Scan failed;2 +VirusDetected;Virus Detected;1 +VirusScanInprogress;Virus Scan In Progress(refresh page);5 \ No newline at end of file diff --git a/app/single-tenant/central-space/demoapp/db/data/sap.capire.bookshop-Authors.csv b/app/single-tenant/central-space/demoapp/db/data/sap.capire.bookshop-Authors.csv new file mode 100644 index 000000000..5272ee157 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/db/data/sap.capire.bookshop-Authors.csv @@ -0,0 +1,5 @@ +ID;name;dateOfBirth;placeOfBirth;dateOfDeath;placeOfDeath +10fef92e-975f-4c41-8045-c58e5c27a040;Emily Brontë;1818-07-30;Thornton, Yorkshire;1848-12-19;Haworth, Yorkshire +d4585e0e-ab3b-4424-b2ac-f2bfa785f068;Charlotte Brontë;1818-04-21;Thornton, Yorkshire;1855-03-31;Haworth, Yorkshire +4cf60975-300d-4dbe-8598-57b02e62bae2;Edgar Allen Poe;1809-01-19;Boston, Massachusetts;1849-10-07;Baltimore, Maryland +df9fb9fa-f121-45b5-8be5-8ff7ad5219a2;Richard Carpenter;1929-08-14;King’s Lynn, Norfolk;2012-02-26;Hertfordshire, England diff --git a/app/single-tenant/central-space/demoapp/db/data/sap.capire.bookshop-Books.csv b/app/single-tenant/central-space/demoapp/db/data/sap.capire.bookshop-Books.csv new file mode 100644 index 000000000..46d63fa5d --- /dev/null +++ b/app/single-tenant/central-space/demoapp/db/data/sap.capire.bookshop-Books.csv @@ -0,0 +1,6 @@ +ID;title;descr;author_ID;stock;price;currency_code;genre_ID +aeeda49f-72f2-4880-be27-a513b2e53040;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.";10fef92e-975f-4c41-8045-c58e5c27a040;12;11.11;GBP;11 +b0056977-4cf5-46a2-ab14-6409ee2e0df1;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.";d4585e0e-ab3b-4424-b2ac-f2bfa785f068;11;12.34;GBP;11 +c7641340-a9be-4673-8dad-785a2505f46e;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.";4cf60975-300d-4dbe-8598-57b02e62bae2;333;13.13;USD;16 +7756b725-cefc-43a2-a3c8-0c9104a349b8;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.";4cf60975-300d-4dbe-8598-57b02e62bae2;555;14;USD;16 +a009c640-434a-4542-ac68-51b400c880ea;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.;df9fb9fa-f121-45b5-8be5-8ff7ad5219a2;22;150;JPY;13 diff --git a/app/single-tenant/central-space/demoapp/db/data/sap.capire.bookshop-Books_texts.csv b/app/single-tenant/central-space/demoapp/db/data/sap.capire.bookshop-Books_texts.csv new file mode 100644 index 000000000..3a3465b28 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/db/data/sap.capire.bookshop-Books_texts.csv @@ -0,0 +1,5 @@ +ID_texts;ID;locale;title;descr +52eee553-266d-4fdd-a5ca-909910e76ae4;aeeda49f-72f2-4880-be27-a513b2e53040;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. +54e58142-f06e-49c1-a51d-138f86cea34e;aeeda49f-72f2-4880-be27-a513b2e53040;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. +bbbf8a88-797d-4790-af1c-1cc857718ee0;b0056977-4cf5-46a2-ab14-6409ee2e0df1;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 +a90d4378-1a3e-48e7-b60b-5670e78807e1;7756b725-cefc-43a2-a3c8-0c9104a349b8;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. diff --git a/app/single-tenant/central-space/demoapp/db/data/sap.capire.bookshop-Genres.csv b/app/single-tenant/central-space/demoapp/db/data/sap.capire.bookshop-Genres.csv new file mode 100644 index 000000000..1ea3793bb --- /dev/null +++ b/app/single-tenant/central-space/demoapp/db/data/sap.capire.bookshop-Genres.csv @@ -0,0 +1,16 @@ +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;21;Autobiography +23;20;Essay +24;20;Speech diff --git a/app/single-tenant/central-space/demoapp/db/package-lock.json b/app/single-tenant/central-space/demoapp/db/package-lock.json new file mode 100644 index 000000000..37a8a994c --- /dev/null +++ b/app/single-tenant/central-space/demoapp/db/package-lock.json @@ -0,0 +1,325 @@ +{ + "name": "deploy", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "deploy", + "dependencies": { + "@sap/hdi-deploy": "^5", + "hdb": "^0" + }, + "engines": { + "node": "^20" + } + }, + "node_modules/@sap/hdi-deploy": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@sap/hdi-deploy/-/hdi-deploy-5.2.2.tgz", + "integrity": "sha512-4QoWgDfT/Bx6CbjRp9vP4+iPtcJpBfXZhaNamQXif4dA+fyraAvO3KALGgTFZEYbU1Aw1D3O+BGIpWZCzTua2A==", + "hasInstallScript": true, + "hasShrinkwrap": true, + "license": "See LICENSE file", + "dependencies": { + "@sap/hdi": "4.5.2", + "@sap/xsenv": "5.2.0", + "async": "3.2.6", + "dotenv": "16.4.5", + "handlebars": "4.7.8", + "micromatch": "4.0.8" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0" + }, + "peerDependencies": { + "@sap/hana-client": "^2 >= 2.6", + "hdb": "^0" + }, + "peerDependenciesMeta": { + "@sap/hana-client": { + "optional": true + }, + "hdb": { + "optional": true + } + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/hana-client": { + "version": "2.20.23", + "hasInstallScript": true, + "optional": true, + "peer": true, + "dependencies": { + "debug": "3.1.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/hdi": { + "version": "4.5.2", + "dependencies": { + "async": "3.2.3" + }, + "engines": { + "node": ">=12 <=20" + }, + "peerDependencies": { + "@sap/hana-client": "^2 >= 2.5", + "hdb": "^0" + }, + "peerDependenciesMeta": { + "@sap/hana-client": { + "optional": true + }, + "hdb": { + "optional": true + } + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/hdi/node_modules/async": { + "version": "3.2.3" + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv": { + "version": "5.2.0", + "dependencies": { + "debug": "4.3.5", + "node-cache": "^5.1.0", + "verror": "1.10.1" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/debug": { + "version": "4.3.5", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/ms": { + "version": "2.1.2" + }, + "node_modules/@sap/hdi-deploy/node_modules/assert-plus": { + "version": "1.0.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/async": { + "version": "3.2.6" + }, + "node_modules/@sap/hdi-deploy/node_modules/braces": { + "version": "3.0.3", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/clone": { + "version": "2.1.2", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/core-util-is": { + "version": "1.0.2" + }, + "node_modules/@sap/hdi-deploy/node_modules/debug": { + "version": "3.1.0", + "optional": true, + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/dotenv": { + "version": "16.4.5", + "engines": { + "node": ">=12" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/extsprintf": { + "version": "1.4.1", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/@sap/hdi-deploy/node_modules/fill-range": { + "version": "7.1.1", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/handlebars": { + "version": "4.7.8", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/hdb": { + "version": "0.19.9", + "optional": true, + "peer": true, + "dependencies": { + "iconv-lite": "^0.4.18" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/iconv-lite": { + "version": "0.4.24", + "optional": true, + "peer": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/is-number": { + "version": "7.0.0", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/micromatch": { + "version": "4.0.8", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/minimist": { + "version": "1.2.8" + }, + "node_modules/@sap/hdi-deploy/node_modules/ms": { + "version": "2.0.0", + "optional": true, + "peer": true + }, + "node_modules/@sap/hdi-deploy/node_modules/neo-async": { + "version": "2.6.2" + }, + "node_modules/@sap/hdi-deploy/node_modules/node-cache": { + "version": "5.1.2", + "dependencies": { + "clone": "2.x" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/picomatch": { + "version": "2.3.1", + "engines": { + "node": ">=8.6" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/safer-buffer": { + "version": "2.1.2", + "optional": true, + "peer": true + }, + "node_modules/@sap/hdi-deploy/node_modules/source-map": { + "version": "0.6.1", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/to-regex-range": { + "version": "5.0.1", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/uglify-js": { + "version": "3.19.2", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/verror": { + "version": "1.10.1", + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/wordwrap": { + "version": "1.0.0" + }, + "node_modules/hdb": { + "version": "0.19.9", + "resolved": "https://registry.npmjs.org/hdb/-/hdb-0.19.9.tgz", + "integrity": "sha512-YtmP4mUmPLANF/HTdvIDIwELYl3H1ld21qRHYfcCW2ol1MXEnze504LoDXxBIuZD7i9LXCT62Bp0Ey5kSRocsg==", + "license": "Apache-2.0", + "dependencies": { + "iconv-lite": "^0.4.18" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + } + } + } + \ No newline at end of file diff --git a/app/single-tenant/central-space/demoapp/db/package.json b/app/single-tenant/central-space/demoapp/db/package.json new file mode 100644 index 000000000..62ba6ff18 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/db/package.json @@ -0,0 +1,15 @@ +{ + "name": "deploy", + "dependencies": { + "hdb": "^0", + "@sap/hdi-deploy": "^5" + }, + "engines": { + "node": "^20" + }, + "scripts": { + "start": "node node_modules/@sap/hdi-deploy/deploy.js --use-hdb", + "build": "npm ci && npx cds build .. --for hana --production" + } + } + \ No newline at end of file diff --git a/app/single-tenant/central-space/demoapp/db/pom.xml b/app/single-tenant/central-space/demoapp/db/pom.xml new file mode 100644 index 000000000..302c9997b --- /dev/null +++ b/app/single-tenant/central-space/demoapp/db/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + + demoapp-parent + customer + ${revision} + + + db + + + + + com.sap.cds + sdm + 1.8.1-SNAPSHOT + + + + + + + com.sap.cds + cds-maven-plugin + ${cds.services.version} + + + cds.clean + + clean + + + + cds.resolve + + resolve + + + + + + + + diff --git a/app/single-tenant/central-space/demoapp/db/schema.cds b/app/single-tenant/central-space/demoapp/db/schema.cds new file mode 100644 index 000000000..5837c3e7c --- /dev/null +++ b/app/single-tenant/central-space/demoapp/db/schema.cds @@ -0,0 +1,98 @@ +using { +Currency, +managed, +cuid, +sap.common.CodeList +} from '@sap/cds/common'; + +namespace sap.capire.bookshop; + +entity Books : managed, cuid { +@mandatory title : localized String(111); +descr : localized String(1111); +@mandatory author : Association to Authors; +genre : Association to Genres; +stock : Integer; +price : Decimal; +currency : Currency; +image : LargeBinary @Core.MediaType: 'image/png'; +virtual isAttachmentsUploadable : Boolean; +virtual isReferencesUploadable : Boolean; + +// top-level chapters composition (root of the nested hierarchy) +cHapters : Composition of many Chapters on cHapters.book = $self; + +// top-level pages composition (same pattern as chapters) +pages : Composition of many Pages on pages.book = $self; + +// keep any other fields as before +} + +entity Authors : managed, cuid { +@mandatory 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 : CodeList { +key ID : Integer; +parent : Association to Genres; +children : Composition of many Genres +on children.parent = $self; +} + +// --- Nested composition entities to emulate deep structure --- + +// entity Chapters : cuid, managed { +// title : String(255); + +// // backlink to parent Book +// book : Association to Books; + +// // each chapter has many sections +// sections : Composition of many Sections on sections.chapter = $self; +// } + +entity Chapters : cuid, managed { + book : Association to Books; + title : String @title: 'Chapter Title'; + description : String; + url : String; + chapterType : String @title: 'Chapter Type'; +} + +/** Adding {Notebooks,Writers} for user service */ +entity Notebooks : managed, cuid { + @mandatory title : localized String(111); + descr : localized String(1111); + @mandatory writer : Association to Writers; + stock : Integer; + price : Decimal; + currency : Currency; + image : LargeBinary @Core.MediaType: 'image/png'; + virtual isAttachmentsUploadable : Boolean; +} + +entity Pages : cuid, managed { + book : Association to Books; + title : String @title: 'Page Title'; + description : String; + url : String; + pageType : String @title: 'Page Type'; +} + +entity Writers : managed, cuid { + @mandatory name : String(111); + dateOfBirth : Date; + dateOfDeath : Date; + placeOfBirth : String; + placeOfDeath : String; + notebooks : Association to many Notebooks + on notebooks.writer = $self; +} + diff --git a/app/single-tenant/central-space/demoapp/mta.yaml b/app/single-tenant/central-space/demoapp/mta.yaml new file mode 100644 index 000000000..273d3a803 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/mta.yaml @@ -0,0 +1,110 @@ +_schema-version: '2.1' +ID: demoappjava +version: 1.0.0 +description: "demoappjava CAP Java Project with UI" +parameters: + enable-parallel-deployments: true +modules: +# --------------------- SERVER MODULE ------------------------ + - name: demoappjava-srv +# ------------------------------------------------------------ + type: java + path: srv + parameters: + memory: 1024M + disk-quota: 512M + buildpack: sap_java_buildpack_jakarta + properties: + SPRING_PROFILES_ACTIVE: cloud,sandbox + JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jre.SAPMachineJRE']" + JBP_CONFIG_SAP_MACHINE_JRE: '{ version: 21.+ }' + REPOSITORY_ID: __REPOSITORY_ID__ # Placeholder for REPOSITORY_ID + INCOMING_REQUEST_TIMEOUT: 3600000 + INCOMING_SESSION_TIMEOUT: 3600000 + INCOMING_CONNECTION_TIMEOUT: 3600000 + build-parameters: + builder: custom + commands: + - mvn clean package -DskipTests=true + build-result: target/*-exec.jar + requires: + - name: demoappjava-hdi-container + - name: demoappjava-public-uaa + - name: cf-logging + - name: sdm + provides: + - name: srv-api + properties: + srv-url: '${default-url}' +# --------------------- DB MODULE --------------------------- + - name: demoappjava-db +# ----------------------------------------------------------- + type: hdb + path: db + parameters: + buildpack: nodejs_buildpack + build-parameters: + builder: custom + commands: + - npm run build + requires: + - name: demoappjava-srv + requires: + - name: demoappjava-hdi-container +# --------------------- APPROUTER MODULE --------------------- + - name: demoappjava-app +# ------------------------------------------------------------ + type: approuter.nodejs + path: app + parameters: + memory: 256M + disk-quota: 512M + properties: + INCOMING_REQUEST_TIMEOUT: 3600000 + INCOMING_SESSION_TIMEOUT: 3600000 + INCOMING_CONNECTION_TIMEOUT: 3600000 + requires: + - name: srv-api + group: destinations + properties: + name: backend + url: ~{srv-url} + forwardAuthToken: true + strictSSL: true + timeout: 3600000 + - name: demoappjava-public-uaa + provides: + - name: app-api + properties: + app-url: '${default-url}' +# --------------------- RESOURCES --------------------- +resources: +# ----------------------------------------------------- + - name: demoappjava-public-uaa + type: org.cloudfoundry.managed-service + parameters: + service: xsuaa + service-plan: application + path: ./xs-security.json + config: # override xsappname as it needs to be unique + xsappname: demoappjava-${org}-${space} + oauth2-configuration: + redirect-uris: + - ~{app-api/app-url}/** + requires: + - name: app-api + - name: demoappjava-hdi-container + type: org.cloudfoundry.managed-service + parameters: + service: hana + service-plan: hdi-shared + - name: cf-logging + type: org.cloudfoundry.managed-service + parameters: + service: application-logs + service-plan: lite + - name: sdm + type: org.cloudfoundry.managed-service + parameters: + service: sdm + service-plan: standard diff --git a/app/single-tenant/central-space/demoapp/package-lock.json b/app/single-tenant/central-space/demoapp/package-lock.json new file mode 100644 index 000000000..307829033 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "demoapp-cds", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "demoapp-cds", + "version": "1.0.0", + "license": "ISC" + } + } +} \ No newline at end of file diff --git a/app/single-tenant/central-space/demoapp/package.json b/app/single-tenant/central-space/demoapp/package.json new file mode 100644 index 000000000..89b583346 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/package.json @@ -0,0 +1,11 @@ +{ + "name": "demoapp-cds", + "version": "1.0.0", + "description": "Generated by cds-services-archetype", + "license": "ISC", + "repository": "", + "sapux": [ + "app/admin-books", + "app/browse" + ] +} diff --git a/app/single-tenant/central-space/demoapp/pom.xml b/app/single-tenant/central-space/demoapp/pom.xml new file mode 100644 index 000000000..272527e30 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/pom.xml @@ -0,0 +1,149 @@ + + + 4.0.0 + + customer + demoapp-parent + ${revision} + pom + + demoapp parent + + + + 1.0.0-SNAPSHOT + + + 21 + 4.1.1 + 3.3.1 + 8.0.2 + + https://nodejs.org/dist/ + UTF-8 + + + + srv + + + + + + + com.sap.cds + cds-services-bom + ${cds.services.version} + pom + import + + + + + org.springframework.boot + spring-boot-dependencies + ${spring.boot.version} + pom + import + + + + + + + github-snapshot + https://maven.pkg.github.com/cap-java/sdm + + true + + + true + + + + + + + + + maven-compiler-plugin + 3.13.0 + + ${jdk.version} + UTF-8 + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + true + + + + + + maven-surefire-plugin + 3.3.0 + + + + + org.codehaus.mojo + flatten-maven-plugin + 1.6.0 + + true + resolveCiFriendliesOnly + + + + flatten + process-resources + + flatten + + + + flatten.clean + clean + + clean + + + + + + + + maven-enforcer-plugin + 3.5.0 + + + Project Structure Checks + + enforce + + + + + 3.5.0 + + + ${jdk.version} + + + + true + + + + + + + diff --git a/app/single-tenant/central-space/demoapp/srv/admin-service.cds b/app/single-tenant/central-space/demoapp/srv/admin-service.cds new file mode 100644 index 000000000..ace6b50d3 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/srv/admin-service.cds @@ -0,0 +1,322 @@ + +using { sap.capire.bookshop as my } from '../db/schema'; +service AdminService @(requires: ['admin','system-user']) { + + entity Books as projection on my.Books; + entity Authors as projection on my.Authors; + entity Chapters as projection on my.Chapters; + entity Pages as projection on my.Pages; + + // Define a return type for the action result + type MoveAttachmentsResult { + failedObjectIds : array of String; + } + + entity Books.attachments as projection on my.Books.attachments + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + annotate AdminService.Books.attachments with @( + Capabilities: {InsertRestrictions: {Insertable: up_.isAttachmentsUploadable}} + ); + + entity Books.references as projection on my.Books.references + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + annotate AdminService.Books.references with @( + Capabilities: {InsertRestrictions: {Insertable: up_.isReferencesUploadable}} + ); + + entity Books.footnotes as projection on my.Books.footnotes + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + entity Pages.attachments as projection on my.Pages.attachments + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + entity Pages.references as projection on my.Pages.references + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + // Chapters projections + entity Chapters.attachments as projection on my.Chapters.attachments + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + entity Chapters.references as projection on my.Chapters.references + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + entity Chapters.footnotes as projection on my.Chapters.footnotes + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + // Side effects on parent entities: structural changes (add/delete) on attachment + // navigation collections trigger a re-read of the uploadable flag on the parent. + annotate AdminService.Books with @( + Common.SideEffects #sdmAttachmentsUploadable: { + SourceEntities: ['attachments'], + TargetProperties: ['isAttachmentsUploadable'] + }, + Common.SideEffects #sdmReferencesUploadable: { + SourceEntities: ['references'], + TargetProperties: ['isReferencesUploadable'] + } + ); + + // Pages footnotes projection + entity Pages.footnotes as projection on my.Pages.footnotes + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; +} diff --git a/app/single-tenant/central-space/demoapp/srv/attachment-extension.cds b/app/single-tenant/central-space/demoapp/srv/attachment-extension.cds new file mode 100644 index 000000000..6ec38cdcc --- /dev/null +++ b/app/single-tenant/central-space/demoapp/srv/attachment-extension.cds @@ -0,0 +1,168 @@ +using {sap.capire.bookshop.Books, sap.capire.bookshop.Chapters, sap.capire.bookshop.Pages, sap.capire.bookshop.Notebooks} from '../db/schema'; +using {sap.attachments.Attachments, sap.attachments.StatusCode} from 'com.sap.cds/sdm'; +using {sap,managed,sap.common.CodeList} from '@sap/cds/common'; + +// keep the original shallow attachments on Books +extend entity Books with { + attachments : Composition of many Attachments @SDM.Attachments:{maxCount: 4, maxCountError:'Only 4 attachments allowed.'}; + references : Composition of many Attachments @SDM.Attachments:{maxCount: 5, maxCountError:'Only 5 attachments allowed.'}; + footnotes : Composition of many Attachments; +} + +extend entity Notebooks with { + attachments : Composition of many Attachments @SDM.Attachments:{maxCount: 4, maxCountError:'Only 4 attachments allowed.'}; +} + +extend entity Chapters with { + attachments: Composition of many Attachments; + references: Composition of many Attachments; + footnotes: Composition of many Attachments; +} + +extend entity Pages with { + attachments: Composition of many Attachments; + references: Composition of many Attachments; + footnotes: Composition of many Attachments; +} + + + +entity Statuses @cds.autoexpose @readonly { + key code : StatusCode; + text : localized String(255); +} + +extend Attachments with { + statusText : Association to Statuses on statusText.code = $self.status; +} + +annotate Books.attachments with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + + + +annotate Books.references with { + content @Validation.Maximum : '30MB'; + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate Chapters.attachments with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate Chapters.references with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate Pages.attachments with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate Pages.references with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate Chapters.footnotes with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate Pages.footnotes with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + + + +extend Attachments with { + customProperty1 : WDIRS_CodeList_TYPE + @SDM.Attachments.AdditionalProperty: { + name: 'Working:DocumentInfoRecordString' + } + @(title: 'DocumentInfoRecordString'); + customProperty2 : Integer + @SDM.Attachments.AdditionalProperty: { + name: 'Working:DocumentInfoRecordInt' + }; + customProperty3 : String + @SDM.Attachments.AdditionalProperty: { + name: 'abc:myId1' + } + @(title: 'id1'); + customProperty4 : String + @SDM.Attachments.AdditionalProperty: { + name: 'abc:myId2' + } + @(title: 'id2'); + customProperty5 : DateTime + @SDM.Attachments.AdditionalProperty: { + name: 'Working:DocumentInfoRecordDate' + } + @(title: 'DocumentInfoRecordDate'); + customProperty6 : Boolean + @SDM.Attachments.AdditionalProperty: { + name: 'Working:DocumentInfoRecordBoolean' + } + @(title: 'DocumentInfoRecordBoolean'); +} + +entity WDIRSCodeList : CodeList { + key code : String(30) @Common.Text : name @Common.TextArrangement: #TextFirst; +}; + +type WDIRS_CodeList_TYPE : Association to one WDIRSCodeList; diff --git a/app/single-tenant/central-space/demoapp/srv/cat-service.cds b/app/single-tenant/central-space/demoapp/srv/cat-service.cds new file mode 100644 index 000000000..1d2cbbab8 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/srv/cat-service.cds @@ -0,0 +1,34 @@ +using {sap.capire.bookshop as my} from '../db/schema'; + +service CatalogService { + + /** 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 + }; + + action submitOrder(book : Books:ID, quantity : Integer) returns { + stock : Integer + }; + + event OrderedBook : { + book : Books:ID; + quantity : Integer; + buyer : String + }; +} diff --git a/app/single-tenant/central-space/demoapp/srv/pom.xml b/app/single-tenant/central-space/demoapp/srv/pom.xml new file mode 100644 index 000000000..cc49287e1 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/srv/pom.xml @@ -0,0 +1,170 @@ + + 4.0.0 + + + demoapp-parent + customer + ${revision} + + + demoapp + jar + + demoapp + + + + + + com.sap.cds + sdm + 1.8.1-SNAPSHOT + + + + + + com.sap.cds + cds-starter-spring-boot + + + + + com.sap.cds + cds-adapter-odata-v4 + runtime + + + + org.springframework.boot + spring-boot-devtools + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + com.h2database + h2 + runtime + + + + org.springframework.boot + spring-boot-starter-security + + + + + ${project.artifactId} + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + false + + + + repackage + + repackage + + + exec + + + + + + + + com.sap.cds + cds-maven-plugin + ${cds.services.version} + + + cds.clean + + clean + + + + + cds.install-node + + install-node + + + ${cdsdk-global} + + + + + cds.install-cdsdk + + install-cdsdk + + + ${cdsdk-global} + + + + + cds.resolve + + resolve + + + + + cds.build + + cds + + + + build --for java + deploy --to h2 --dry > "${project.basedir}/src/main/resources/schema-h2.sql" + + + + + + cds.generate + + generate + + + cds.gen + true + true + + + + + + + + + + + cdsdk-global + + + env.CDSDK_GLOBAL + true + + + + true + + + + diff --git a/app/single-tenant/central-space/demoapp/srv/src/main/java/customer/demoapp/Application.java b/app/single-tenant/central-space/demoapp/srv/src/main/java/customer/demoapp/Application.java new file mode 100644 index 000000000..35ca27fdf --- /dev/null +++ b/app/single-tenant/central-space/demoapp/srv/src/main/java/customer/demoapp/Application.java @@ -0,0 +1,13 @@ +package customer.demoapp; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/app/single-tenant/central-space/demoapp/srv/src/main/java/customer/demoapp/handlers/AdminServiceHandler.java b/app/single-tenant/central-space/demoapp/srv/src/main/java/customer/demoapp/handlers/AdminServiceHandler.java new file mode 100644 index 000000000..4281f4957 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/srv/src/main/java/customer/demoapp/handlers/AdminServiceHandler.java @@ -0,0 +1,230 @@ +package customer.demoapp.handlers; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import com.sap.cds.ql.Insert; +import com.sap.cds.ql.cqn.CqnAnalyzer; +import com.sap.cds.ql.cqn.CqnComparisonPredicate; +import com.sap.cds.ql.cqn.CqnConnectivePredicate; +import com.sap.cds.ql.cqn.CqnElementRef; +import com.sap.cds.ql.cqn.CqnLiteral; +import com.sap.cds.ql.cqn.CqnPredicate; +import com.sap.cds.ql.cqn.CqnReference; +import com.sap.cds.ql.cqn.CqnSelect; +import com.sap.cds.ql.cqn.CqnStructuredTypeRef; +import com.sap.cds.services.EventContext; +import com.sap.cds.services.cds.ApplicationService; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.On; +import com.sap.cds.services.handler.annotations.ServiceName; + +import java.util.List; + +import cds.gen.adminservice.AdminService_; +import cds.gen.adminservice.BooksAttachments_; + +/** + * Handler for AdminService operations including creating attachments in active entity state. + */ +@Component +@ServiceName(AdminService_.CDS_NAME) +public class AdminServiceHandler implements EventHandler { + + private static final Logger logger = LoggerFactory.getLogger(AdminServiceHandler.class); + + @Autowired + @Qualifier("AdminService") + private ApplicationService adminService; + + /** + * Handler for createAttachmentInActive action. + */ + @On(event = "createAttachmentInActive") + public void createAttachmentInActive(EventContext context) { + String targetEntity = context.getTarget().getQualifiedName(); + logger.info("=== createAttachmentInActive triggered for entity: {} ===", targetEntity); + + // Guard: When CAP invokes this during draft activation (edit+save), + // the "in" parameter contains existing attachment rows. + // A user-initiated button click sends "in" as null/empty (RequiresSelection: false). + // Skip execution if "in" has items — that means it's a framework save, not a user click. + Object inParam = context.get("in"); + if (inParam instanceof List && !((List) inParam).isEmpty()) { + logger.info("Skipping createAttachmentInActive — triggered by framework save (in has {} items), not user click", ((List) inParam).size()); + context.setCompleted(); + return; + } + + try { + // Extract the parent entity ID from CQN + CqnSelect cqn = (CqnSelect) context.get("cqn"); + CqnAnalyzer analyzer = CqnAnalyzer.create(context.getModel()); + Map rootKeys = analyzer.analyze(cqn).rootKeys(); + logger.info("Root keys: {}", rootKeys); + + // Extract the immediate parent ID. + // For non-nested entities (e.g., Books.attachments), rootKeys has {up__ID: bookID}. + // For nested entities (e.g., Chapters.attachments via composition path + // Books(bookID)/chapters(chapterID)/attachments), rootKeys only has {ID: bookID} + // and the Chapter ID is in the penultimate CQN path segment's filter. + String parentId = extractParentId(cqn, rootKeys); + + if (parentId == null || parentId.isEmpty()) { + logger.error("Could not extract parent ID from CQN. Root keys: {}", rootKeys); + context.setCompleted(); + throw new RuntimeException("Parent entity ID is required to create attachment."); + } + + logger.info("Creating attachment for parent ID: {} in facet: {}", parentId, targetEntity); + + // Create attachment with unique filename (timestamp prevents any duplicate issues) + String attachmentId = createAttachmentWithContent(parentId, targetEntity); + logger.info("Attachment created successfully with ID: {}", attachmentId); + + context.setCompleted(); + + } catch (Exception e) { + logger.error("Failed to create attachment: {}", e.getMessage(), e); + context.setCompleted(); + throw new RuntimeException("Failed to create attachment: " + e.getMessage(), e); + } + } + + /** + * Creates an attachment record with content in the active entity state. + * Uses a timestamp-based unique filename to prevent duplicate issues. + */ + private String createAttachmentWithContent(String parentId, String targetEntity) throws IOException { + String attachmentId = UUID.randomUUID().toString(); + + // Use timestamp in filename to guarantee uniqueness + String timestamp = DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss-SSS") + .withZone(ZoneId.systemDefault()) + .format(Instant.now()); + String fileName = "attachment-" + timestamp + ".txt"; + + String sampleContent = "Sample Attachment\n" + + "Created: " + Instant.now() + "\n" + + "Parent ID: " + parentId + "\n" + + "Facet: " + targetEntity + "\n" + + "Attachment ID: " + attachmentId; + + InputStream contentStream = new ByteArrayInputStream(sampleContent.getBytes(StandardCharsets.UTF_8)); + + Map attachmentData = new HashMap<>(); + attachmentData.put("ID", attachmentId); + attachmentData.put("up__ID", parentId); + attachmentData.put("fileName", fileName); + attachmentData.put("mimeType", "text/plain"); + attachmentData.put("note", "Created programmatically in active entity"); + attachmentData.put("content", contentStream); + + // Determine which entity to insert into based on the target + // The target will be like "AdminService.Books.attachments" or "AdminService.Chapters.attachments" etc. + String insertTarget = targetEntity; + logger.info("Inserting attachment into: {}", insertTarget); + + Insert insert = Insert.into(insertTarget).entry(attachmentData); + adminService.run(insert); + + return attachmentId; + } + + /** + * Extracts the immediate parent entity's ID from the CQN. + * + * For non-nested entities (e.g., Books.attachments): + * CQN: SELECT from AdminService.Books.attachments WHERE up__ID = 'bookID' + * rootKeys = {up__ID: bookID} → up__ID found directly. + * + * For nested entities (e.g., Chapters.attachments via composition path): + * CQN: SELECT from AdminService.Books[ID='bookID'].chapters[ID='chapterID'].attachments + * rootKeys = {ID: bookID} → up__ID NOT found. + * Fix: traverse CQN path segments and extract ID from the penultimate segment + * (which represents the immediate parent entity, e.g., chapters[ID='chapterID']). + */ + private String extractParentId(CqnSelect cqn, Map rootKeys) { + // Case 1: Direct entity set — rootKeys has up__ID + Object upId = rootKeys.get("up__ID"); + if (upId != null) { + logger.info("Found up__ID in rootKeys: {}", upId); + return upId.toString(); + } + + // Case 2: Nested composition path — traverse CQN ref segments + try { + if (cqn.from().isRef()) { + CqnStructuredTypeRef ref = cqn.from().asRef(); + List segments = ref.segments(); + logger.info("CQN path has {} segments", segments.size()); + + if (segments.size() >= 2) { + // Penultimate segment is the immediate parent (e.g., "chapters") + CqnReference.Segment parentSegment = segments.get(segments.size() - 2); + logger.info("Parent segment: {}, has filter: {}", + parentSegment.id(), parentSegment.filter().isPresent()); + + if (parentSegment.filter().isPresent()) { + String parentId = extractIdFromPredicate(parentSegment.filter().get()); + if (parentId != null) { + logger.info("Extracted parent ID from CQN segment '{}': {}", + parentSegment.id(), parentId); + return parentId; + } + } + } + } + } catch (Exception e) { + logger.warn("Could not extract parent ID from CQN path segments: {}", e.getMessage()); + } + + // Fallback: use ID from rootKeys (correct for non-nested, wrong for nested) + Object id = rootKeys.get("ID"); + if (id != null) { + logger.warn("Using fallback ID from rootKeys (may be wrong for nested entities): {}", id); + return id.toString(); + } + + return null; + } + + /** + * Recursively extracts the "ID" value from a CQN predicate. + * Handles simple comparisons (ID = 'value') and conjunctions (ID = 'value' AND IsActiveEntity = true). + */ + private String extractIdFromPredicate(CqnPredicate predicate) { + if (predicate instanceof CqnComparisonPredicate) { + CqnComparisonPredicate comp = (CqnComparisonPredicate) predicate; + if (comp.left() instanceof CqnElementRef && comp.right() instanceof CqnLiteral) { + String fieldName = ((CqnElementRef) comp.left()).lastSegment(); + if ("ID".equals(fieldName)) { + return ((CqnLiteral) comp.right()).value().toString(); + } + } + } else if (predicate instanceof CqnConnectivePredicate) { + // Conjunction (AND) or disjunction (OR) — check each child + for (CqnPredicate child : ((CqnConnectivePredicate) predicate).predicates()) { + String id = extractIdFromPredicate(child); + if (id != null) { + return id; + } + } + } + return null; + } +} diff --git a/app/single-tenant/central-space/demoapp/srv/src/main/java/customer/demoapp/handlers/CatalogServiceHandler.java b/app/single-tenant/central-space/demoapp/srv/src/main/java/customer/demoapp/handlers/CatalogServiceHandler.java new file mode 100644 index 000000000..72f5d969b --- /dev/null +++ b/app/single-tenant/central-space/demoapp/srv/src/main/java/customer/demoapp/handlers/CatalogServiceHandler.java @@ -0,0 +1,63 @@ +package customer.demoapp.handlers; + +import java.util.stream.Stream; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.sap.cds.ql.Select; +import com.sap.cds.ql.Update; +import com.sap.cds.services.cds.CqnService; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.After; +import com.sap.cds.services.handler.annotations.On; +import com.sap.cds.services.handler.annotations.ServiceName; +import com.sap.cds.services.persistence.PersistenceService; + +import cds.gen.catalogservice.Books; +import cds.gen.catalogservice.Books_; +import cds.gen.catalogservice.CatalogService_; +import cds.gen.catalogservice.OrderedBook; +import cds.gen.catalogservice.OrderedBookContext; +import cds.gen.catalogservice.SubmitOrderContext; +import cds.gen.catalogservice.SubmitOrderContext.ReturnType; + +@Component +@ServiceName(CatalogService_.CDS_NAME) +public class CatalogServiceHandler implements EventHandler { + + @Autowired + private PersistenceService db; + + @On + public void submitOrder(SubmitOrderContext context) { + // decrease and update stock in database + db.run(Update.entity(Books_.class).byId(context.getBook()).set(b -> b.stock(), s -> s.minus(context.getQuantity()))); + + // read new stock from database + Books book = db.run(Select.from(Books_.class).where(b -> b.ID().eq(context.getBook()))).single(Books.class); + + // return new stock to client + ReturnType result = SubmitOrderContext.ReturnType.create(); + result.setStock(book.getStock()); + + OrderedBook orderedBook = OrderedBook.create(); + orderedBook.setBook(book.getId()); + orderedBook.setQuantity(context.getQuantity()); + orderedBook.setBuyer(context.getUserInfo().getName()); + + OrderedBookContext orderedBookEvent = OrderedBookContext.create(); + orderedBookEvent.setData(orderedBook); + context.getService().emit(orderedBookEvent); + + context.setResult(result); + } + + @After(event = CqnService.EVENT_READ) + public void discountBooks(Stream books) { + books.filter(b -> b.getTitle() != null && b.getStock() != null) + .filter(b -> b.getStock() > 200) + .forEach(b -> b.setTitle(b.getTitle() + " (discounted)")); + } + +} \ No newline at end of file diff --git a/app/single-tenant/central-space/demoapp/srv/src/main/resources/application.yaml b/app/single-tenant/central-space/demoapp/srv/src/main/resources/application.yaml new file mode 100644 index 000000000..a95dc604c --- /dev/null +++ b/app/single-tenant/central-space/demoapp/srv/src/main/resources/application.yaml @@ -0,0 +1,11 @@ +--- +spring: + config: + activate: + on-profile: default + sql: + init: + schema-locations: classpath:schema-h2.sql + data-source: + auto-config: + enabled: false \ No newline at end of file diff --git a/app/single-tenant/central-space/demoapp/srv/src/main/resources/messages.properties b/app/single-tenant/central-space/demoapp/srv/src/main/resources/messages.properties new file mode 100644 index 000000000..8e99a85d0 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/srv/src/main/resources/messages.properties @@ -0,0 +1 @@ +SDM.Attachments.maxCountError = Maximum number of attachments reached in English diff --git a/app/single-tenant/central-space/demoapp/srv/src/test/java/customer/demoapp/handlers/CatalogServiceHandlerTest.java b/app/single-tenant/central-space/demoapp/srv/src/test/java/customer/demoapp/handlers/CatalogServiceHandlerTest.java new file mode 100644 index 000000000..77d4d5509 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/srv/src/test/java/customer/demoapp/handlers/CatalogServiceHandlerTest.java @@ -0,0 +1,42 @@ +package customer.demoapp.handlers; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.stream.Stream; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import cds.gen.catalogservice.Books; + +class CatalogServiceHandlerTest { + + private CatalogServiceHandler handler = new CatalogServiceHandler(); + private Books book = Books.create(); + + @BeforeEach + public void prepareBook() { + book.setTitle("title"); + } + + @Test + void testDiscount() { + book.setStock(500); + handler.discountBooks(Stream.of(book)); + assertEquals("title (discounted)", book.getTitle()); + } + + @Test + void testNoDiscount() { + book.setStock(100); + handler.discountBooks(Stream.of(book)); + assertEquals("title", book.getTitle()); + } + + @Test + void testNoStockAvailable() { + handler.discountBooks(Stream.of(book)); + assertEquals("title", book.getTitle()); + } + +} diff --git a/app/single-tenant/central-space/demoapp/srv/user-service.cds b/app/single-tenant/central-space/demoapp/srv/user-service.cds new file mode 100644 index 000000000..de6444756 --- /dev/null +++ b/app/single-tenant/central-space/demoapp/srv/user-service.cds @@ -0,0 +1,10 @@ +using {sap.capire.bookshop as my} from '../db/schema'; + +service UserService @(requires: [ + 'admin', + 'system-user' +]) { + @odata.draft.enabled + entity Notebooks as projection on my.Notebooks; + entity Writers as projection on my.Writers; +} diff --git a/app/single-tenant/central-space/demoapp/xs-security.json b/app/single-tenant/central-space/demoapp/xs-security.json new file mode 100644 index 000000000..941dd117b --- /dev/null +++ b/app/single-tenant/central-space/demoapp/xs-security.json @@ -0,0 +1,18 @@ +{ "xsappname": "demoappjava-${org}-${space}", + "tenant-mode": "dedicated", + "scopes": [ + { + "name": "$XSAPPNAME.admin", + "description": "admin" + } + ], + "role-templates": [ + { + "name": "admin", + "description": "generated", + "scope-references": [ + "$XSAPPNAME.admin" + ] + } + ] +} diff --git a/app/single-tenant/personal-space/attachments-demo-app.capnb b/app/single-tenant/personal-space/attachments-demo-app.capnb new file mode 100644 index 000000000..13a6377c4 --- /dev/null +++ b/app/single-tenant/personal-space/attachments-demo-app.capnb @@ -0,0 +1,244 @@ +[ + { + "kind": 1, + "language": "markdown", + "value": "# CDS SDM CAP Notebook\n\nThis CAP notebook creates a CAP Java demoapp with sample data and enhances the app with the CAP feature for attachments.\nAll needed enhancements are done. \nFor more information check the project [README](../README.md). ", + "outputs": [] + }, + { + "kind": 1, + "language": "markdown", + "value": "## Add the App with Sample Data\n`cds init` is used to create a basic CAP Java app with sample data.", + "outputs": [] + }, + { + "kind": 2, + "language": "shell", + "value": "cds init demoapp --add java,sample\n", + "outputs": [ + { + "mime": "text/plain", + "value": "Creating new CAP project" + } + ] + }, + { + "kind": 2, + "language": "shell", + "value": "cd demoapp", + "outputs": [ + { + "mime": "text/plain", + "value": "\n" + } + ] + }, + { + "kind": 1, + "language": "markdown", + "value": "## Add Enhancements for the Datamodel\nThe `books` entity will be enhanced with the `attachments` composition.\n\nTo be able to use the `sdm` datamodel a `pom.xml` needs to be added with the maven dependency for the feature.\nThe version for the dependency is taken from the file `version.txt`. \nThis file will be updated if a new version is created in the repository.\n\nOnce the `pom.xml` is available and the version is set a `mvn clean verify` is executed.\nWith the the `resolve` goal of the `cds-maven-plugin` is executed which copies the `cds`-files from the feature in the `target` folder of the `db` module.\n\nOnce available in the `target` folder it will be found and can be used in the data models.", + "outputs": [] + }, + { + "kind": 2, + "language": "shell", + "value": "%%writefile \"db/attachment-extension.cds\"\nusing {sap.capire.bookshop.Books} from './schema';\nusing {sap.attachments.Attachments} from`com.sap.cds/sdm`;\n\nextend entity Books with {\n attachments : Composition of many Attachments;\n}\n\nentity Statuses @cds.autoexpose @readonly {\n key code : StatusCode;\n text : localized String(255);\n}\n\nextend Attachments with {\n statusText : Association to Statuses on statusText.code = $self.status;\n}\n\nannotate Books.attachments with {\n status @(\n Common.Text: {\n $value: ![statusText.text],\n ![@UI.TextArrangement]: #TextOnly\n },\n ValueList: {entity:'Statuses'},\n sap.value.list: 'fixed-values'\n );\n}\n", + "outputs": [ + { + "mime": "text/html", + "value": "Wrote cell content to file demoapp/db/attachment-extension.cds.\n" + } + ] + }, + { + "kind": 2, + "language": "shell", + "value": "", + "outputs": [ + { + "mime": "text/html", + "value": "Wrote cell content to file demoapp/db/data/Statuses.csv.\n" + } + ] + }, + { + "kind": 2, + "language": "shell", + "value": "", + "outputs": [ + { + "mime": "text/html", + "value": "Wrote cell content to file demoapp/db/data/Statuses_texts.csv.\n" + } + ] + }, + { + "kind": 2, + "language": "shell", + "value": "%%writefile \"db/pom.xml\"\n\n\n\t4.0.0\n\t\n\t\tdemoapp-parent\n\t\tcustomer\n\t\t${revision}\n\t\n\n\tdb\n\n \n \n \n com.sap.cds\n sdm\n 1.0.0\n \n \n\t\n\t\n\t\t\n\t\t\t\n\t\t\t\tcom.sap.cds\n\t\t\t\tcds-maven-plugin\n\t\t\t\t${cds.services.version}\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\tcds.clean\n\t\t\t\t\t\t\n\t\t\t\t\t\t\tclean\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\tcds.resolve\n\t\t\t\t\t\t\n\t\t\t\t\t\t\tresolve\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\n\t\n\n", + "outputs": [ + { + "mime": "text/html", + "value": "Wrote cell content to file demoapp/db/pom.xml.\n" + } + ] + }, + { + "kind": 2, + "language": "shell", + "value": "cd db", + "outputs": [ + { + "mime": "text/plain", + "value": "\n" + } + ] + }, + { + "kind": 2, + "language": "java", + "value": "Path versionPath = Paths.get(\"../../version.txt\");\nString version;\nif (Files.exists(versionPath)){\n version = Files.readString(versionPath);\n System.out.println(\"Using version from 'version.txt': \" + version);\n}else{\n version = \"1.0.2\";\n System.out.println(\"Using hard coded version: \" + version);\n}\nPath pomPath = Paths.get(\"pom.xml\");\nStream lines = Files.lines(pomPath);\nList replaced = lines.map(line -> line.replaceAll(\"attachment_version\", version)).collect(Collectors.toList());\nFiles.write(pomPath, replaced);\nlines.close();", + "outputs": [ + { + "mime": "text/plain", + "value": "Using version from 'version.txt': 1.0.2\n\n\n" + } + ] + }, + { + "kind": 2, + "language": "shell", + "value": "mvn clean compile", + "outputs": [ + { + "mime": "text/plain", + "value": "" + } + ] + }, + { + "kind": 1, + "language": "markdown", + "value": "## Service Changes\n\nThe service module `srv` of the demo project needs to be updated with the maven dependency for `sdm`.\nThis dependency has included the logic to correctly handle attachments and call the `AtacchmentService`.\n\nAlso here, the version is taken from the `version.txt` which is updated in case a new version in the repository is created.", + "outputs": [] + }, + { + "kind": 2, + "language": "shell", + "value": "cd ../srv", + "outputs": [ + { + "mime": "text/plain", + "value": "\n" + } + ] + }, + { + "kind": 1, + "language": "markdown", + "value": "add the following dependency to the `srv/pom.xml`:\n```\n\n com.sap.cds\n sdm\n 1.0.0-SNAPSHOT\n\n``` ", + "outputs": [] + }, + { + "kind": 2, + "language": "java", + "value": "\nPath versionPath = Paths.get(\"../../version.txt\");\nString version;\nif (Files.exists(versionPath)){\n version = Files.readString(versionPath);\n System.out.println(\"Using version from 'version.txt': \" + version);\n}else{\n version = \"1.0.2\";\n System.out.println(\"Using hard coded version: \" + version);\n}\n\nString filePath = \"pom.xml\";\ntry {\n String pom = Files.readString(Path.of(filePath));\n String searchString = \"\";\n Pattern pattern = Pattern.compile(searchString);\n Matcher matcher = pattern.matcher(pom);\n\n if (matcher.find()) {\n System.out.println(\"String found at position: \" + matcher.start());\n } else {\n System.out.println(\"String not found\");\n }\n\n String newDependency = \"\\n\\n \\n com.sap.cds\\n sdm\\n \" + version + \"\\n \\n\\n\";\n int insertPos = matcher.end();\n pom = pom.substring(0, insertPos) + newDependency + pom.substring(insertPos);\n\n Files.writeString(Path.of(filePath), pom);\n\n} catch (IOException e) {\n e.printStackTrace();\n}", + "outputs": [ + { + "mime": "text/plain", + "value": "Using version from 'version.txt': 1.0.2\n\nString found at position: 540\n\n" + } + ] + }, + { + "kind": 2, + "language": "shell", + "value": "cd ..", + "outputs": [ + { + "mime": "text/plain", + "value": "\n" + } + ] + }, + { + "kind": 1, + "language": "markdown", + "value": "## UI Enhancements\n", + "outputs": [] + }, + { + "kind": 1, + "language": "markdown", + "value": "### UI Facet\n\nA UI facet is added for the attachments in the `AdminService`. Because the facet is only added in this service, only this services shows the attachments on the UI.\n\nThe following facet is added:\n\n```\n{\n $Type : 'UI.ReferenceFacet',\n ID : 'AttachmentsFacet',\n Label : '{i18n>attachments}',\n Target: 'attachments/@UI.LineItem'\\n \n}\n```", + "outputs": [] + }, + { + "kind": 2, + "language": "java", + "value": "String filePath = \"app/admin-books/fiori-service.cds\";\n\ntry {\n String cds = Files.readString(Path.of(filePath));\n String searchString = \"Target:\\\\s*'@UI\\\\.FieldGroup#Details'\\\\s*},\";\n Pattern pattern = Pattern.compile(searchString);\n Matcher matcher = pattern.matcher(cds);\n\n if (matcher.find()) {\n System.out.println(\"String found at position: \" + matcher.start());\n } else {\n System.out.println(\"String not found\");\n }\n\n String newFacet = \"\\n {\\n $Type : 'UI.ReferenceFacet',\\n ID : 'AttachmentsFacet',\\n Label : '{i18n>attachments}',\\n Target: 'attachments/@UI.LineItem'\\n },\";\n int insertPos = matcher.end();\n cds = cds.substring(0, insertPos) + newFacet + cds.substring(insertPos);\n\n Files.writeString(Path.of(filePath), cds);\n\n} catch (IOException e) {\n e.printStackTrace();\n}", + "outputs": [ + { + "mime": "text/plain", + "value": "String found at position: 546\n\n" + } + ] + }, + { + "kind": 1, + "language": "markdown", + "value": "### Texts\n\nThe i18n property file is enhanced with the texts for the attachments to show correct texts on the UI.", + "outputs": [] + }, + { + "kind": 2, + "language": "shell", + "value": "cd app/_i18n", + "outputs": [ + { + "mime": "text/plain", + "value": "\n" + } + ] + }, + { + "kind": 2, + "language": "java", + "value": "String filePath = \"i18n.properties\";\n\nList properties = new ArrayList<>();\nproperties.add(\"\\n\");\nproperties.add(\"#Attachment properties\\n\");\nproperties.add(\"attachment_content = Content\\n\");\nproperties.add(\"attachment_mimeType = Mime Type\\n\");\nproperties.add(\"attachment_fileName = File Name\\n\");\nproperties.add(\"attachment_status = Status\\n\");\nproperties.add(\"attachment_note = Notes\\n\");\nproperties.add(\"attachment = Attachment\\n\");\nproperties.add(\"attachments = Attachments\");\n\nfor (String property: properties){\n try {\n Files.write(Paths.get(filePath), property.getBytes(), StandardOpenOption.APPEND);\n } catch (IOException e) {\n e.printStackTrace();\n }\n}\n", + "outputs": [ + { + "mime": "text/plain", + "value": "\n" + } + ] + }, + { + "kind": 1, + "language": "markdown", + "value": "## Build the Service\n\nRun `mvn clean compile` on the service to compile the models with all changes.", + "outputs": [] + }, + { + "kind": 2, + "language": "shell", + "value": "cd ../../srv\nmvn clean compile", + "outputs": [ + { + "mime": "text/plain", + "value": "" + } + ] + }, + { + "kind": 1, + "language": "markdown", + "value": "## Start the Service\n\n\nThe service can now be started with the following command in the `srv` module:\n\n```\nmvn cds:watch\n```\n\nAfter the service is startet the UI can be opened with:\n\n[http://localhost:8080](http://localhost:8080)\n\nNavigate to the index.html of the webapp and use user `admin` with password `admin`. \n\nUsing the tile `Manage Books` the attachments can be used in the detail area of the books.\n\nUsing the tile `Browse Books` no attachments are shown.", + "outputs": [] + }, + { + "kind": 1, + "language": "markdown", + "value": "", + "outputs": [] + } +] \ No newline at end of file diff --git a/app/single-tenant/personal-space/demoapp/.cdsrc.json b/app/single-tenant/personal-space/demoapp/.cdsrc.json new file mode 100644 index 000000000..169ddb72c --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/.cdsrc.json @@ -0,0 +1,5 @@ +{ + "sql": { + "native_hana_associations" : false + } +} diff --git a/app/single-tenant/personal-space/demoapp/.gitignore b/app/single-tenant/personal-space/demoapp/.gitignore new file mode 100644 index 000000000..c161f228e --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/.gitignore @@ -0,0 +1,31 @@ +**/gen/ +**/edmx/ +*.db +*.sqlite +*.sqlite-wal +*.sqlite-shm +schema*.sql +default-env.json + +**/bin/ +**/target/ +.flattened-pom.xml +.classpath +.project +.settings + +**/node/ +**/node_modules/ + +**/.mta/ +*.mtar + +*.log* +gc_history* +hs_err* +*.tgz +*.iml + +.vscode +.idea +.reloadtrigger diff --git a/app/single-tenant/personal-space/demoapp/app/_i18n/i18n.properties b/app/single-tenant/personal-space/demoapp/app/_i18n/i18n.properties new file mode 100644 index 000000000..6bca9e0ec --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/_i18n/i18n.properties @@ -0,0 +1,66 @@ +Books = Books +Book = Book +ID = ID +Title = Title +Author = Author +Authors = Authors +AuthorID = Author ID +AuthorName = Author Name +Name = Name +Age = Age +Stock = Stock +Order = Order +Orders = Orders +Price = Price +Genre = Genre +#Attachment properties +attachment_content = Attachment +attachment_mimeType = Mime Type +attachment_fileName = Filename +attachment_status = Status +attachment_note = Note +attachment = Attachment +attachments = Attachments +reference = Reference +references = References +uploadStatus = Upload Status +type=Type + +#XFLD,50: Label for a section +Chapters=Chapters + +#XFLD,120: Label for entity +Chapter=Chapter + +#XFLD,120: Label for a field +ChapterTitle=Chapter Title + +#XFLD,120: Label for a field +ChapterType=Chapter Type + +#XFLD,50: Label for a section +Pages=Pages + +#XFLD,120: Label for entity +Page=Page + +#XFLD,120: Label for a field +PageTitle=Page Title + +#XFLD,120: Label for a field +PageType=Page Type + +#XFLD,50: Label for a section +Footnotes=Footnotes + +#XFLD,120: Label for a field +Description=Description + +#XFLD,120: Label for a field +URL=URL + +#XFLD,50: Label for a section +GeneralInformation=General Information + +#XFLD,50: Label for a section +Attachments=Attachments diff --git a/app/single-tenant/personal-space/demoapp/app/_i18n/i18n_de.properties b/app/single-tenant/personal-space/demoapp/app/_i18n/i18n_de.properties new file mode 100644 index 000000000..7046fa3e8 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/_i18n/i18n_de.properties @@ -0,0 +1,51 @@ +Books = Bücher +Book = Buch +ID = ID +Title = Titel +Author = Autor +Authors = Autoren +AuthorID = ID des Autors +AuthorName = Name des Autors +Name = Name +Age = Alter +Stock = Bestand +Order = Bestellung +Orders = Bestellungen +Price = Preis +Genre = Genre + +#XFLD,50: Label for a section +Chapters=Kapitel + +#XFLD,120: Label for entity +Chapter=Kapitel + +#XFLD,120: Label for a field +ChapterTitle=Kapitel Titel + +#XFLD,120: Label for a field +ChapterType=Kapitel Typ + +#XFLD,50: Label for a section +Pages=Seiten + +#XFLD,120: Label for entity +Page=Seite + +#XFLD,120: Label for a field +PageTitle=Seiten Titel + +#XFLD,120: Label for a field +PageType=Seiten Typ + +#XFLD,50: Label for a section +Footnotes=Fußnoten + +#XFLD,120: Label for a field +Description=Beschreibung + +#XFLD,120: Label for a field +URL=URL + +#XFLD,50: Label for a section +GeneralInformation=Allgemeine Informationen \ No newline at end of file diff --git a/app/single-tenant/personal-space/demoapp/app/admin-books/fiori-service.cds b/app/single-tenant/personal-space/demoapp/app/admin-books/fiori-service.cds new file mode 100644 index 000000000..146ea4cfd --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/admin-books/fiori-service.cds @@ -0,0 +1,375 @@ +using {AdminService} from '../../srv/admin-service.cds'; + +//////////////////////////////////////////////////////////////////////////// +// +// 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', + ID : 'AttachmentsFacet', + Label : '{i18n>attachments}', + Target: 'attachments/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'ReferencesFacet', + Label : '{i18n>references}', + Target: 'references/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'FootnotesFacet', + Label : 'Footnotes', + Target: 'footnotes/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>Admin}', + Target: '@UI.FieldGroup#Admin' + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>Chapters}', + ID : 'i18nChapters', + Target : 'cHapters/@UI.LineItem#i18nChapters', + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>Pages}', + ID : 'i18nPages', + Target : 'pages/@UI.LineItem#i18nPages', + }, + ], + 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} + ]} +}); + +////////// + +// Chapters annotations +annotate AdminService.Chapters with @title : '{i18n>Chapter}'; + +annotate AdminService.Books.chapters with @( + title : '{i18n>Chapters}' +); + +annotate AdminService.Chapters with @( + UI.LineItem : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>ChapterTitle}', + }, + { + $Type : 'UI.DataField', + Value : chapterType, + Label : '{i18n>ChapterType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + ], + UI.LineItem #i18nChapters : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>ChapterTitle}', + }, + { + $Type : 'UI.DataField', + Value : chapterType, + Label : '{i18n>ChapterType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + ] +); + +annotate AdminService.Chapters with @( + UI.HeaderInfo : { + Title : { + $Type : 'UI.DataField', + Value : title, + }, + TypeName : '{i18n>Chapter}', + TypeNamePlural : '{i18n>Chapters}', + Description : { + $Type : 'UI.DataField', + Value : description, + }, + } +); + +annotate AdminService.Chapters with @( + UI.FieldGroup #GeneratedGroup1 : { + $Type : 'UI.FieldGroupType', + Data : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>ChapterTitle}', + }, + { + $Type : 'UI.DataField', + Value : chapterType, + Label : '{i18n>ChapterType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + { + $Type : 'UI.DataField', + Value : url, + Label : '{i18n>URL}', + }, + ], + }, + UI.Facets : [ + { + $Type : 'UI.ReferenceFacet', + ID : 'GeneratedFacet1', + Label : '{i18n>GeneralInformation}', + Target : '@UI.FieldGroup#GeneratedGroup1', + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'AttachmentsFacet', + Label : '{i18n>attachments}', + Target : 'attachments/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'ReferencesFacet', + Label : '{i18n>references}', + Target : 'references/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'FootnotesFacet', + Label : '{i18n>Footnotes}', + Target : 'footnotes/@UI.LineItem' + } + ] +); + +////////// + +// Pages annotations +annotate AdminService.Pages with @title : '{i18n>Page}'; + +annotate AdminService.Books.pages with @( + title : '{i18n>Pages}' +); + +annotate AdminService.Pages with @( + UI.LineItem : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>PageTitle}', + }, + { + $Type : 'UI.DataField', + Value : pageType, + Label : '{i18n>PageType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + ], + UI.LineItem #i18nPages : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>PageTitle}', + }, + { + $Type : 'UI.DataField', + Value : pageType, + Label : '{i18n>PageType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + ] +); + +annotate AdminService.Pages with @( + UI.HeaderInfo : { + Title : { + $Type : 'UI.DataField', + Value : title, + }, + TypeName : '{i18n>Page}', + TypeNamePlural : '{i18n>Pages}', + Description : { + $Type : 'UI.DataField', + Value : description, + }, + } +); + +annotate AdminService.Pages with @( + UI.FieldGroup #GeneratedGroup1 : { + $Type : 'UI.FieldGroupType', + Data : [ + { + $Type : 'UI.DataField', + Value : title, + Label : '{i18n>PageTitle}', + }, + { + $Type : 'UI.DataField', + Value : pageType, + Label : '{i18n>PageType}', + }, + { + $Type : 'UI.DataField', + Value : description, + Label : '{i18n>Description}', + }, + { + $Type : 'UI.DataField', + Value : url, + Label : '{i18n>URL}', + }, + ], + }, + UI.Facets : [ + { + $Type : 'UI.ReferenceFacet', + ID : 'GeneratedFacet1', + Label : '{i18n>GeneralInformation}', + Target : '@UI.FieldGroup#GeneratedGroup1', + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'AttachmentsFacet', + Label : '{i18n>attachments}', + Target : 'attachments/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'ReferencesFacet', + Label : '{i18n>references}', + Target : 'references/@UI.LineItem' + }, + { + $Type : 'UI.ReferenceFacet', + ID : 'FootnotesFacet', + Label : '{i18n>Footnotes}', + Target : 'footnotes/@UI.LineItem' + } + ] +); + + +//////////////////////////////////////////////////////////// +// +// 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' + }, + ] +}); + +annotate AdminService.Books.texts with { + ID @UI.Hidden; + ID_texts @UI.Hidden; +}; + +// Add Value Help for Locales +annotate AdminService.Books.texts { + locale @( + ValueList.entity: 'Languages', + Common.ValueListWithFixedValues, //show as drop down, not a dialog + ) +}; + +// In addition we need to expose Languages through AdminService as a target for ValueList +using {sap} from '@sap/cds/common'; + +extend service AdminService { + @readonly + entity Languages as projection on sap.common.Languages; +} + +// Workaround for Fiori popup for asking user to enter a new UUID on Create +annotate AdminService.Books with { + ID @Core.Computed; +} + +// Show Genre as drop down, not a dialog +annotate AdminService.Books with { + genre @Common.ValueListWithFixedValues; +} + +annotate AdminService.Books.attachments with { + customProperty1 @Common.ValueListWithFixedValues; +} diff --git a/app/single-tenant/personal-space/demoapp/app/admin-books/package.json b/app/single-tenant/personal-space/demoapp/app/admin-books/package.json new file mode 100644 index 000000000..5acd4af83 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/admin-books/package.json @@ -0,0 +1,13 @@ +{ + "name": "admin-books", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" + } + \ No newline at end of file diff --git a/app/single-tenant/personal-space/demoapp/app/admin-books/webapp/Component.js b/app/single-tenant/personal-space/demoapp/app/admin-books/webapp/Component.js new file mode 100644 index 000000000..e98677ee9 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/admin-books/webapp/Component.js @@ -0,0 +1,8 @@ +sap.ui.define(["sap/fe/core/AppComponent"], function (AppComponent) { + "use strict"; + return AppComponent.extend("books.Component", { + metadata: { manifest: "json" } + }); +}); + +/* eslint no-undef:0 */ diff --git a/app/single-tenant/personal-space/demoapp/app/admin-books/webapp/controller/custom.controller.js b/app/single-tenant/personal-space/demoapp/app/admin-books/webapp/controller/custom.controller.js new file mode 100644 index 000000000..8cb074e7b --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/admin-books/webapp/controller/custom.controller.js @@ -0,0 +1,141 @@ +sap.ui.define( + [ + "sap/ui/core/mvc/ControllerExtension", + "sap/m/library", + "sap/ui/core/format/DateFormat" + ], + function (ControllerExtension, library, DateFormat) { + "use strict"; + const ChangeCategoryEnum = { + created: "Created", + updated: "Changed" + // Add more mappings as needed + }; + + return ControllerExtension.extend("books.controller.custom", { + isDownloadEnabled: function(oBindingContext, aSelectedContexts) { + if (!aSelectedContexts || aSelectedContexts.length === 0) { + return false; + } + return !aSelectedContexts.some(function(oContext) { + return oContext.getProperty("mimeType") === "application/internet-shortcut"; + }); + }, + onRowPress: function(oContext) { + this.base.editFlow + .invokeAction("AdminService.openAttachment", { + contexts: oContext.getParameter("bindingContext") + }) + .then(function (res) { + let odataurl = ""; + if(res.getObject().value == "None") { + const lastSlashIndex = res.oModel.getServiceUrl().lastIndexOf('/'); + let str = res.oModel.getServiceUrl(); + if (lastSlashIndex !== -1) { + str = str.substring(0, lastSlashIndex) + str.substring(lastSlashIndex + 1); + } + odataurl = str+res.oBinding.oContext.sPath+"/content"; + } else { + odataurl = res.getObject().value; + } + library.URLHelper.redirect(odataurl, true); + + }); + }, + onChangelogPress: function(oContext, aSelectedContexts) { + var that =this; + this.base.editFlow + .invokeAction("AdminService.changelog", { + contexts: aSelectedContexts + }) + .then(function (res) { + console.log("Result",res[0].value.getObject().value); + that.updateChangeLogInPropertiesModel(res[0].value.getObject().value); + }); + }, + updateChangeLogInPropertiesModel: function (oChangeLogsForObjectResponse) { + const aChangeLogs = []; + const fileName = JSON.parse(oChangeLogsForObjectResponse).filename; + console.log("Filename: ", fileName); + const aChangeLogsObject = JSON.parse(oChangeLogsForObjectResponse)["changeLogs"]; + console.log("ChangeLogsObject:\n", aChangeLogsObject); + // Take latest changes at the top + for (let idx = aChangeLogsObject.length - 1; idx >= 0; idx--) { + const oChangeLogEntry = aChangeLogsObject[idx]; + const sLastModifiedBy = oChangeLogEntry["user"]; + const sChangeType = oChangeLogEntry["operation"]; + const sChangeTime = oChangeLogEntry["time"]; + let dateTimeFormat = DateFormat.getDateTimeInstance(sap.ui.getCore().getConfiguration().getLocale()); + let changedDate = new Date(sChangeTime); + let changedTime = changedDate?dateTimeFormat.format(new Date(changedDate)) : "" ; + const oChangeLog = { + changedOn: changedTime, + changedBy: sLastModifiedBy, + changeType: ChangeCategoryEnum[sChangeType] + }; + aChangeLogs.push(oChangeLog); + console.log("ChangeLog:\n", oChangeLog); + } + + this.logFragment= this.base.getExtensionAPI().loadFragment({ + name: "books.fragments.changelog", + controller: this + }); + var that = this; + this.logFragment.then(function (dialog) { + if(dialog){ + dialog.attachEventOnce("afterClose", function () { + dialog.destroy(); + }); + var oModel = new sap.ui.model.json.JSONModel(); + oModel.setSizeLimit(100000); + oModel.setData(aChangeLogs); + that.getView().setModel(oModel, "changelog"); + dialog.setTitle(fileName); + dialog.open() + } + }); + }, + close: function (closeBtn) { + closeBtn.getSource().getParent().close(); + }, + onDownloadPress: function(oContext, aSelectedContexts) { + var sIds = aSelectedContexts.map(function(oCtx) { + return oCtx.getObject().ID; + }).join(","); + this.base.editFlow + .invokeAction("AdminService.downloadSelectedAttachments", { + contexts: aSelectedContexts[0], + parameterValues: [{ name: "ids", value: sIds }], + skipParameterDialog: true + }) + .then(function (res) { + var sJsonResponse = res.getObject().value; + var aEntries = JSON.parse(sJsonResponse); + aEntries.forEach(function (oEntry) { + if (oEntry.status === "success") { + if (oEntry.linkUrl) { + window.open(oEntry.linkUrl, "_blank"); + } else if (oEntry.content) { + var byteString = atob(oEntry.content); + var aBytes = new Uint8Array(byteString.length); + for (var i = 0; i < byteString.length; i++) { + aBytes[i] = byteString.charCodeAt(i); + } + var oBlob = new Blob([aBytes], { type: oEntry.mimeType || "application/octet-stream" }); + var sUrl = URL.createObjectURL(oBlob); + var oLink = document.createElement("a"); + oLink.href = sUrl; + oLink.download = oEntry.fileName || "download"; + document.body.appendChild(oLink); + oLink.click(); + document.body.removeChild(oLink); + URL.revokeObjectURL(sUrl); + } + } + }); + }); + } + }); + } +); \ No newline at end of file diff --git a/app/single-tenant/personal-space/demoapp/app/admin-books/webapp/fragments/changelog.fragment.xml b/app/single-tenant/personal-space/demoapp/app/admin-books/webapp/fragments/changelog.fragment.xml new file mode 100644 index 000000000..1a1462526 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/admin-books/webapp/fragments/changelog.fragment.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+ + +
+
\ No newline at end of file diff --git a/app/single-tenant/personal-space/demoapp/app/admin-books/webapp/i18n/i18n.properties b/app/single-tenant/personal-space/demoapp/app/admin-books/webapp/i18n/i18n.properties new file mode 100644 index 000000000..9a23ee40a --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/admin-books/webapp/i18n/i18n.properties @@ -0,0 +1,3 @@ +appTitle=Manage Books +appSubTitle=Manage bookshop inventory +appDescription=Manage your bookshop inventory with ease. diff --git a/app/single-tenant/personal-space/demoapp/app/admin-books/webapp/i18n/i18n_de.properties b/app/single-tenant/personal-space/demoapp/app/admin-books/webapp/i18n/i18n_de.properties new file mode 100644 index 000000000..01d56a22c --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/admin-books/webapp/i18n/i18n_de.properties @@ -0,0 +1,3 @@ +appTitle=Bücher verwalten +appSubTitle=Verwalten Sie den Bestand der Buchhandlungen +appDescription=Verwalten Sie den Bestand Ihrer Buchhandlung ganz einfach. diff --git a/app/single-tenant/personal-space/demoapp/app/admin-books/webapp/manifest.json b/app/single-tenant/personal-space/demoapp/app/admin-books/webapp/manifest.json new file mode 100644 index 000000000..7bf86c760 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/admin-books/webapp/manifest.json @@ -0,0 +1,477 @@ +{ + "_version": "1.49.0", + "sap.app": { + "applicationVersion": { + "version": "1.0.0" + }, + "id": "demoapp.admin-books", + "type": "application", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "i18n": "i18n/i18n.properties", + "dataSources": { + "AdminService": { + "uri": "/odata/v4/AdminService/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + }, + "crossNavigation": { + "inbounds": { + "Books-manage": { + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "semanticObject": "Books", + "action": "manage" + } + } + } + }, + "sap.ui": { + "technology": "UI5", + "fullWidth": false, + "deviceTypes": { + "desktop": true, + "tablet": true, + "phone": true + } + }, + "sap.ui5": { + "dependencies": { + "minUI5Version": "1.115.1", + "libs": { + "sap.fe.templates": {} + } + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "i18n/i18n.properties" + }, + "": { + "dataSource": "AdminService", + "settings": { + "synchronizationMode": "None", + "operationMode": "Server", + "autoExpandSelect": true, + "earlyRequests": true, + "groupProperties": { + "default": { + "submit": "Auto" + } + } + } + } + }, + "routing": { + "routes": [ + { + "pattern": ":?query:", + "name": "BooksList", + "target": "BooksList" + }, + { + "pattern": "Books({key}):?query:", + "name": "BooksDetails", + "target": "BooksDetails" + }, + { + "pattern": "Books({key}/author({key2}):?query:", + "name": "AuthorsDetails", + "target": "AuthorsDetails" + }, + { + "pattern": "Books({key})/cHapters({key2}):?query:", + "name": "chaptersObjectPage", + "target": "ChaptersObjectPage" + }, + { + "pattern": "Books({key})/pages({key2}):?query:", + "name": "pagesObjectPage", + "target": "PagesObjectPage" + } + ], + "targets": { + "BooksList": { + "type": "Component", + "id": "BooksList", + "name": "sap.fe.templates.ListReport", + "options": { + "settings": { + "entitySet": "Books", + "initialLoad": true, + "navigation": { + "Books": { + "detail": { + "route": "BooksDetails" + } + } + } + } + } + }, + "BooksDetails": { + "type": "Component", + "id": "BooksDetailsList", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings": { + "entitySet": "Books", + "navigation": { + "Chapters": { + "detail": { + "route": "ChaptersObjectPage" + } + }, + "Pages": { + "detail": { + "route": "PagesObjectPage" + } + } + }, + "controlConfiguration": { + "attachments/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.books.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.books.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.books.controller.custom.isDownloadEnabled", + "press": ".extension.books.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "references/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.books.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.books.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.books.controller.custom.isDownloadEnabled", + "press": ".extension.books.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "footnotes/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.books.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.books.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.books.controller.custom.isDownloadEnabled", + "press": ".extension.books.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + } + } + } + } + }, + "ChaptersObjectPage": { + "type": "Component", + "id": "ChaptersObjectPage", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings": { + "editableHeaderContent": false, + "entitySet": "Chapters", + "controlConfiguration": { + "attachments/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.books.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.books.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.books.controller.custom.isDownloadEnabled", + "press": ".extension.books.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "references/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.books.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.books.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.books.controller.custom.isDownloadEnabled", + "press": ".extension.books.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "footnotes/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.books.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.books.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.books.controller.custom.isDownloadEnabled", + "press": ".extension.books.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + } + } + } + } + }, + "PagesObjectPage": { + "type": "Component", + "id": "PagesObjectPage", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings": { + "editableHeaderContent": false, + "entitySet": "Pages", + "navigation": {}, + "controlConfiguration": { + "attachments/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.books.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.books.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.books.controller.custom.isDownloadEnabled", + "press": ".extension.books.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "references/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.books.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.books.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.books.controller.custom.isDownloadEnabled", + "press": ".extension.books.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + }, + "footnotes/@com.sap.vocabularies.UI.v1.LineItem": { + "tableSettings": { + "type": "ResponsiveTable", + "selectionMode": "Multi", + "rowPress": ".extension.books.controller.custom.onRowPress" + }, + "actions": { + "changelog": { + "enableOnSelect": "single", + "text": "Change Log", + "requiresSelection": true, + "press": ".extension.books.controller.custom.onChangelogPress", + "command": "COMMON", "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + }, + "download": { + "text": "Download", + "requiresSelection": true, + "enabled": ".extension.books.controller.custom.isDownloadEnabled", + "press": ".extension.books.controller.custom.onDownloadPress", + "position": { + "anchor": "StandardAction::Create", + "placement": "After" + } + } + } + } + } + } + } + }, + "SectionsObjectPage": { + "type": "Component", + "id": "SectionsObjectPage", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings": { + "editableHeaderContent": false, + "entitySet": "Sections", + "navigation": {} + } + } + }, + "AuthorsDetails": { + "type": "Component", + "id": "AuthorsDetailsList", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings": { + "entitySet": "Authors" + } + } + } + } + }, + "extends": { + "extensions": { + "sap.ui.controllerExtensions": { + "sap.fe.templates.ObjectPage.ObjectPageController#books::BooksDetailsList": { + "controllerName": "books.controller.custom" + }, + "sap.fe.templates.ObjectPage.ObjectPageController#books::ChaptersObjectPage": { + "controllerName": "books.controller.custom" + }, + "sap.fe.templates.ObjectPage.ObjectPageController#books::PagesObjectPage": { + "controllerName": "books.controller.custom" + } + } + } + }, + "contentDensities": { + "compact": true, + "cozy": true + } + }, + "sap.fiori": { + "registrationIds": [], + "archeType": "transactional" + } +} diff --git a/app/single-tenant/personal-space/demoapp/app/appconfig/fioriSandboxConfig.json b/app/single-tenant/personal-space/demoapp/app/appconfig/fioriSandboxConfig.json new file mode 100644 index 000000000..ff2ac499b --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/appconfig/fioriSandboxConfig.json @@ -0,0 +1,95 @@ +{ + "services": { + "LaunchPage": { + "adapter": { + "config": { + "catalogs": [], + "groups": [ + { + "id": "Bookshop", + "title": "Bookshop", + "isPreset": true, + "isVisible": true, + "isGroupLocked": false, + "tiles": [ + { + "id": "BrowseBooks", + "tileType": "sap.ushell.ui.tile.StaticTile", + "properties": { + "title": "Browse Books", + "targetURL": "#Books-display" + } + } + ] + }, + { + "id": "Administration", + "title": "Administration", + "isPreset": true, + "isVisible": true, + "isGroupLocked": false, + "tiles": [ + { + "id": "ManageBooks", + "tileType": "sap.ushell.ui.tile.StaticTile", + "properties": { + "title": "Manage Books", + "targetURL": "#Books-manage" + } + } + ] + } + ] + } + } + }, + "NavTargetResolution": { + "config": { + "enableClientSideTargetResolution": true + } + }, + "ClientSideTargetResolution": { + "adapter": { + "config": { + "inbounds": { + "BrowseBooks": { + "semanticObject": "Books", + "action": "display", + "title": "Browse Books", + "signature": { + "parameters": { + "Books.ID": { + "renameTo": "ID" + }, + "Authors.books.ID": { + "renameTo": "ID" + } + }, + "additionalParameters": "ignored" + }, + "resolutionResult": { + "applicationType": "SAPUI5", + "additionalInformation": "SAPUI5.Component=bookshop", + "url": "browse/webapp" + } + }, + "ManageBooks": { + "semanticObject": "Books", + "action": "manage", + "title": "Manage Books", + "signature": { + "parameters": {}, + "additionalParameters": "allowed" + }, + "resolutionResult": { + "applicationType": "SAPUI5", + "additionalInformation": "SAPUI5.Component=books", + "url": "admin-books/webapp" + } + } + } + } + } + } + } +} diff --git a/app/single-tenant/personal-space/demoapp/app/browse/fiori-service.cds b/app/single-tenant/personal-space/demoapp/app/browse/fiori-service.cds new file mode 100644 index 000000000..5ae5c9d70 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/browse/fiori-service.cds @@ -0,0 +1,56 @@ +using {CatalogService} from '../../srv/cat-service.cds'; + +//////////////////////////////////////////////////////////////////////////// +// +// 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 List Page +// +annotate CatalogService.Books with @(UI: { + SelectionFields: [ + ID, + price, + currency_code + ], + LineItem : [ + { + Value: ID, + Label: '{i18n>Title}' + }, + { + Value: author, + Label: '{i18n>Author}' + }, + {Value: genre.name}, + {Value: price}, + {Value: currency.symbol}, + ] +}); diff --git a/app/single-tenant/personal-space/demoapp/app/browse/webapp/Component.js b/app/single-tenant/personal-space/demoapp/app/browse/webapp/Component.js new file mode 100644 index 000000000..4020679f8 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/browse/webapp/Component.js @@ -0,0 +1,7 @@ +sap.ui.define(["sap/fe/core/AppComponent"], function(AppComponent) { + "use strict"; + return AppComponent.extend("bookshop.Component", { + metadata: { manifest: "json" } + }); +}); +/* eslint no-undef:0 */ diff --git a/app/single-tenant/personal-space/demoapp/app/browse/webapp/i18n/i18n.properties b/app/single-tenant/personal-space/demoapp/app/browse/webapp/i18n/i18n.properties new file mode 100644 index 000000000..21436e8e4 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/browse/webapp/i18n/i18n.properties @@ -0,0 +1,3 @@ +appTitle=Browse Books +appSubTitle=Find all your favorite books +appDescription=This application lets you find the next books you want to read. diff --git a/app/single-tenant/personal-space/demoapp/app/browse/webapp/i18n/i18n_de.properties b/app/single-tenant/personal-space/demoapp/app/browse/webapp/i18n/i18n_de.properties new file mode 100644 index 000000000..ea86c3f29 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/browse/webapp/i18n/i18n_de.properties @@ -0,0 +1,3 @@ +appTitle=Bücher anschauen +appSubTitle=Finden sie ihre nächste Lektüre +appDescription=Finden Sie die nachsten Bücher, die Sie lesen möchten. diff --git a/app/single-tenant/personal-space/demoapp/app/browse/webapp/manifest.json b/app/single-tenant/personal-space/demoapp/app/browse/webapp/manifest.json new file mode 100644 index 000000000..5754f332c --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/browse/webapp/manifest.json @@ -0,0 +1,138 @@ +{ + "_version": "1.49.0", + "sap.app": { + "id": "demoapp.browse", + "applicationVersion": { + "version": "1.0.0" + }, + "type": "application", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "i18n": "i18n/i18n.properties", + "dataSources": { + "CatalogService": { + "uri": "/odata/v4/CatalogService/", + "type": "OData", + "settings": { + "odataVersion": "4.0" + } + } + }, + "crossNavigation": { + "inbounds": { + "intent1": { + "signature": { + "parameters": { + "Books.ID": { + "renameTo": "ID" + }, + "Authors.books.ID": { + "renameTo": "ID" + } + }, + "additionalParameters": "ignored" + }, + "semanticObject": "Books", + "action": "display", + "title": "{{appTitle}}", + "subTitle": "{{appSubTitle}}", + "icon": "sap-icon://course-book", + "indicatorDataSource": { + "dataSource": "CatalogService", + "path": "Books/$count", + "refresh": 1800 + } + } + } + } + }, + "sap.ui": { + "technology": "UI5", + "fullWidth": false, + "deviceTypes": { + "desktop": true, + "tablet": true, + "phone": true + } + }, + "sap.ui5": { + "dependencies": { + "minUI5Version": "1.115.1", + "libs": { + "sap.fe.templates": {} + } + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "i18n/i18n.properties" + }, + "": { + "dataSource": "CatalogService", + "settings": { + "synchronizationMode": "None", + "operationMode": "Server", + "autoExpandSelect": true, + "earlyRequests": true, + "groupProperties": { + "default": { + "submit": "Auto" + } + } + } + } + }, + "routing": { + "routes": [ + { + "pattern": ":?query:", + "name": "BooksList", + "target": "BooksList" + }, + { + "pattern": "Books({key}):?query:", + "name": "BooksDetails", + "target": "BooksDetails" + } + ], + "targets": { + "BooksList": { + "type": "Component", + "id": "BooksList", + "name": "sap.fe.templates.ListReport", + "options": { + "settings": { + "entitySet": "Books", + "initialLoad": true, + "navigation": { + "Books": { + "detail": { + "route": "BooksDetails" + } + } + } + } + } + }, + "BooksDetails": { + "type": "Component", + "id": "BooksDetailsList", + "name": "sap.fe.templates.ObjectPage", + "options": { + "settings": { + "entitySet": "Books" + } + } + } + } + }, + "contentDensities": { + "compact": true, + "cozy": true + } + }, + "sap.fiori": { + "registrationIds": [], + "archeType": "transactional" + } +} diff --git a/app/single-tenant/personal-space/demoapp/app/common.cds b/app/single-tenant/personal-space/demoapp/app/common.cds new file mode 100644 index 000000000..198a18c9e --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/common.cds @@ -0,0 +1,1070 @@ +/* + Common Annotations shared by all apps +*/ + +using { sap.capire.bookshop as my } from '../db/schema'; +using { sap.common, sap.common.Currencies } from '@sap/cds/common'; + +//////////////////////////////////////////////////////////////////////////// +// +// Books Lists +// +annotate my.Books with @( + Common.SemanticKey: [ID], + UI: { + Identification: [{ Value: title }], + SelectionFields: [ + ID, + author_ID, + price, + currency_code + ], + LineItem: [ + { Value: ID, Label: '{i18n>Title}' }, + { Value: author.ID, Label: '{i18n>Author}' }, + { Value: genre.name }, + { Value: stock }, + { Value: price }, + { Value: currency.symbol }, + ] + } +) { + ID @Common: { + SemanticObject: 'Books', + Text: title, + TextArrangement: #TextOnly + }; + author @ValueList.entity: 'Authors'; +}; + +annotate Currencies with { + symbol @Common.Label: '{i18n>Currency}'; +} + +//////////////////////////////////////////////////////////////////////////// +// +// Books Details +// +annotate my.Books with @(UI : {HeaderInfo : { + TypeName : '{i18n>Book}', + TypeNamePlural: '{i18n>Books}', + Title : { Value: title }, + Description : { Value: author.name } +}, }); + +//////////////////////////////////////////////////////////////////////////// +// +// Attachments Details +// + +annotate my.Books.attachments with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Attachment}', + TypeNamePlural: '{i18n>Attachments}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Attachments', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + uploadStatus @(title: '{i18n>uploadStatus}', Common.Text : uploadStatusNav.name, Common.TextArrangement : #TextOnly); + type @(title: '{i18n>type}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} +annotate Attachments with @Common: {SideEffects #ContentChanged: { + SourceProperties: [content], + TargetProperties: ['status'], + TargetEntities : [Books.attachments] +}}{}; + +annotate my.Books.references with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Attachment}', + TypeNamePlural: '{i18n>Attachments}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Attachments', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + uploadStatus @(title: '{i18n>uploadStatus}', Common.Text : uploadStatusNav.name, Common.TextArrangement : #TextOnly); + type @(title: '{i18n>type}'); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Books.footnotes with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Attachment}', + TypeNamePlural: '{i18n>Attachments}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Attachments', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + uploadStatus @(title: '{i18n>uploadStatus}', Common.Text : uploadStatusNav.name, Common.TextArrangement : #TextOnly); + type @(title: '{i18n>type}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Chapters.attachments with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Attachment}', + TypeNamePlural: '{i18n>Attachments}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Attachments', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + uploadStatus @(title: '{i18n>uploadStatus}', Common.Text : uploadStatusNav.name, Common.TextArrangement : #TextOnly); + type @(title: '{i18n>type}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Chapters.references with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Reference}', + TypeNamePlural: '{i18n>References}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy References', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + uploadStatus @(title: '{i18n>uploadStatus}', Common.Text : uploadStatusNav.name, Common.TextArrangement : #TextOnly); + type @(title: '{i18n>type}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Chapters.footnotes with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Footnote}', + TypeNamePlural: '{i18n>Footnotes}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Footnotes', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + uploadStatus @(title: '{i18n>uploadStatus}', Common.Text : uploadStatusNav.name, Common.TextArrangement : #TextOnly); + type @(title: '{i18n>type}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Pages.attachments with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Attachment}', + TypeNamePlural: '{i18n>Attachments}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Attachments', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + uploadStatus @(title: '{i18n>uploadStatus}', Common.Text : uploadStatusNav.name, Common.TextArrangement : #TextOnly); + type @(title: '{i18n>type}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Pages.references with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Reference}', + TypeNamePlural: '{i18n>References}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy References', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + uploadStatus @(title: '{i18n>uploadStatus}', Common.Text : uploadStatusNav.name, Common.TextArrangement : #TextOnly); + type @(title: '{i18n>type}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +annotate my.Pages.footnotes with @UI: { + HeaderInfo: { + $Type : 'UI.HeaderInfoType', + TypeName : '{i18n>Footnote}', + TypeNamePlural: '{i18n>Footnotes}', + }, + LineItem : [ + { + $Type : 'UI.DataFieldForAction', + Action: 'AdminService.createAttachmentInActive', + Label : 'Create Attachment', + Inline: false, + RequiresSelection: false, + ![@UI.Hidden]: {$edmJson: {$Ne: [ {$Path: 'IsActiveEntity'}, true ]}} + }, + {Value: type, @HTML5.CssDefaults: {width: '10%'}}, + {Value: fileName, @HTML5.CssDefaults: {width: '20%'}}, + {Value: content, @HTML5.CssDefaults: {width: '0%'}}, + {Value: createdAt, @HTML5.CssDefaults: {width: '15%'}}, + {Value: createdBy, @HTML5.CssDefaults: {width: '15%'}}, + {Value: note, @HTML5.CssDefaults: {width: '20%'}}, + { + Value : uploadStatus, + Criticality: uploadStatusNav.criticality, + @Common.FieldControl: #ReadOnly, + @HTML5.CssDefaults: {width: '20%'} }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Copy Footnotes', + Action: 'AdminService.copyAttachments', + }, + { + $Type : 'UI.DataFieldForAction', + Label : 'Move Attachments', + Action: 'AdminService.moveAttachments', + }, + { + $Type : 'UI.DataFieldForActionGroup', + ID : 'TableActionGroup', + Label : 'Create', + ![@UI.Hidden]: {$edmJson: {$Eq: [ {$Path: 'IsActiveEntity'}, true ]}}, + Actions: [ + { + $Type : 'UI.DataFieldForAction', + Label : 'Link', + Action: 'AdminService.createLink' + } + ] + }, + { + @UI.Hidden: {$edmJson: { + $If: [ + { $Eq: [ { $Path: 'IsActiveEntity' }, true ] }, + true, + { + $If: [ + { $Ne: [ { $Path: 'mimeType' }, 'application/internet-shortcut' ] }, + true, + false + ] + } + ] + } + }, + $Type : 'UI.DataFieldForAction', + Label : 'Edit Link', + Action: 'AdminService.editLink', + Inline: true, + IconUrl: 'sap-icon://edit', + @HTML5.CssDefaults: {width: '4%'} + } + ], +} +{ + note @(title: '{i18n>Note}'); + fileName @(title: '{i18n>Filename}'); + modifiedAt @(odata.etag: null); + content + @Core.ContentDisposition: { Filename: fileName } + @(title: '{i18n>Attachment}'); + uploadStatus @(title: '{i18n>uploadStatus}', Common.Text : uploadStatusNav.name, Common.TextArrangement : #TextOnly); + type @(title: '{i18n>type}'); + folderId @UI.Hidden; + repositoryId @UI.Hidden ; + objectId @UI.Hidden ; + mimeType @UI.Hidden; + status @UI.Hidden; +} + +//////////////////////////////////////////////////////////////////////////// +// +// Books Elements +// +annotate my.Books with { + ID @title: '{i18n>ID}'; + 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}' @Measures.ISOCurrency: currency_code; + stock @title: '{i18n>Stock}'; + descr @title: '{i18n>Description}' @UI.MultiLineText; + image @title: '{i18n>Image}'; +} + +//////////////////////////////////////////////////////////////////////////// +// +// Genres List +// +annotate my.Genres with @( + Common.SemanticKey: [name], + UI: { + SelectionFields: [name], + LineItem: [ + { Value: name }, + { + Value: parent.name, + Label: 'Main Genre' + }, + ], + } +); + +annotate my.Genres with { + ID @Common.Text : name @Common.TextArrangement : #TextOnly; +} + +//////////////////////////////////////////////////////////////////////////// +// +// 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: [ID], + UI: { + Identification : [{ Value: name}], + SelectionFields: [ name ], + LineItem : [ + { Value: ID }, + { Value: dateOfBirth }, + { Value: dateOfDeath }, + { Value: placeOfBirth }, + { Value: placeOfDeath }, + ], + } +) { + ID @Common: { + SemanticObject: 'Authors', + Text: name, + TextArrangement: #TextOnly, + }; +}; + +//////////////////////////////////////////////////////////////////////////// +// +// 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}'; + 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' + } + ], + FieldGroup #Details: {Data : [ + { Value: name }, + { Value: symbol }, + { Value: code }, + { Value: descr } + ]} +}); diff --git a/app/single-tenant/personal-space/demoapp/app/index.html b/app/single-tenant/personal-space/demoapp/app/index.html new file mode 100644 index 000000000..1b0453bef --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/index.html @@ -0,0 +1,32 @@ + + + + + + + + Bookshop + + + + + + + + + + diff --git a/app/single-tenant/personal-space/demoapp/app/package.json b/app/single-tenant/personal-space/demoapp/app/package.json new file mode 100644 index 000000000..fa9d34967 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/package.json @@ -0,0 +1,9 @@ +{ + "name": "approuter", + "dependencies": { + "@sap/approuter": "16.8.2" + }, + "scripts": { + "start": "node node_modules/@sap/approuter/approuter.js" + } +} diff --git a/app/single-tenant/personal-space/demoapp/app/services.cds b/app/single-tenant/personal-space/demoapp/app/services.cds new file mode 100644 index 000000000..87e7b310f --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/services.cds @@ -0,0 +1,6 @@ +/* + This model controls what gets served to Fiori frontends... +*/ +using from './common'; +using from './browse/fiori-service'; +using from './admin-books/fiori-service'; diff --git a/app/single-tenant/personal-space/demoapp/app/xs-app.json b/app/single-tenant/personal-space/demoapp/app/xs-app.json new file mode 100644 index 000000000..069ad9797 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/app/xs-app.json @@ -0,0 +1,85 @@ +{ + "welcomeFile": "/app/index.html", + "authenticationMethod": "route", + "routes": [ + { + "source": "^/odata/(.*)$", + "target": "/odata/$1", + "destination": "backend", + "authenticationType": "xsuaa", + "csrfProtection": false + }, + { + "source": "^/app/(.*)$", + "cacheControl": "no-cache, no-store, must-revalidate", + "target": "$1", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/appconfig/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/browse/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/admin-books/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/orders/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/reviews/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/notes/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/addresses/webapp/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/vue/(.*)$", + "localDir": "./", + "authenticationType": "xsuaa" + }, + { + "source": "^/api/admin/(.*)", + "authenticationType": "xsuaa", + "destination": "backend" + }, + { + "source": "^/api/browse/(.*)", + "authenticationType": "xsuaa", + "destination": "backend" + }, + { + "source": "^/api/review/(.*)", + "authenticationType": "xsuaa", + "destination": "backend" + }, + { + "source": "^/api/notes/(.*)", + "authenticationType": "xsuaa", + "destination": "backend" + }, + { + "source": "^/api/(.*)$", + "authenticationType": "none", + "destination": "backend" + } + ] +} diff --git a/app/single-tenant/personal-space/demoapp/db/data/WDIRSCodeList.csv b/app/single-tenant/personal-space/demoapp/db/data/WDIRSCodeList.csv new file mode 100644 index 000000000..d2bbc28bf --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/db/data/WDIRSCodeList.csv @@ -0,0 +1,4 @@ +code;name +A;Promotions type A +B;Promotions type B +C;Promotions type C \ No newline at end of file diff --git a/app/single-tenant/personal-space/demoapp/db/data/sap.attachments-UploadScanStates.csv b/app/single-tenant/personal-space/demoapp/db/data/sap.attachments-UploadScanStates.csv new file mode 100644 index 000000000..8432b60db --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/db/data/sap.attachments-UploadScanStates.csv @@ -0,0 +1,6 @@ +code;name;criticality +uploading;Uploading;5 +Success;Success;3 +Failed;Scan failed;2 +VirusDetected;Virus Detected;1 +VirusScanInprogress;Virus Scan In Progress(refresh page);5 \ No newline at end of file diff --git a/app/single-tenant/personal-space/demoapp/db/data/sap.capire.bookshop-Authors.csv b/app/single-tenant/personal-space/demoapp/db/data/sap.capire.bookshop-Authors.csv new file mode 100644 index 000000000..5272ee157 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/db/data/sap.capire.bookshop-Authors.csv @@ -0,0 +1,5 @@ +ID;name;dateOfBirth;placeOfBirth;dateOfDeath;placeOfDeath +10fef92e-975f-4c41-8045-c58e5c27a040;Emily Brontë;1818-07-30;Thornton, Yorkshire;1848-12-19;Haworth, Yorkshire +d4585e0e-ab3b-4424-b2ac-f2bfa785f068;Charlotte Brontë;1818-04-21;Thornton, Yorkshire;1855-03-31;Haworth, Yorkshire +4cf60975-300d-4dbe-8598-57b02e62bae2;Edgar Allen Poe;1809-01-19;Boston, Massachusetts;1849-10-07;Baltimore, Maryland +df9fb9fa-f121-45b5-8be5-8ff7ad5219a2;Richard Carpenter;1929-08-14;King’s Lynn, Norfolk;2012-02-26;Hertfordshire, England diff --git a/app/single-tenant/personal-space/demoapp/db/data/sap.capire.bookshop-Books.csv b/app/single-tenant/personal-space/demoapp/db/data/sap.capire.bookshop-Books.csv new file mode 100644 index 000000000..46d63fa5d --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/db/data/sap.capire.bookshop-Books.csv @@ -0,0 +1,6 @@ +ID;title;descr;author_ID;stock;price;currency_code;genre_ID +aeeda49f-72f2-4880-be27-a513b2e53040;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.";10fef92e-975f-4c41-8045-c58e5c27a040;12;11.11;GBP;11 +b0056977-4cf5-46a2-ab14-6409ee2e0df1;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.";d4585e0e-ab3b-4424-b2ac-f2bfa785f068;11;12.34;GBP;11 +c7641340-a9be-4673-8dad-785a2505f46e;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.";4cf60975-300d-4dbe-8598-57b02e62bae2;333;13.13;USD;16 +7756b725-cefc-43a2-a3c8-0c9104a349b8;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.";4cf60975-300d-4dbe-8598-57b02e62bae2;555;14;USD;16 +a009c640-434a-4542-ac68-51b400c880ea;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.;df9fb9fa-f121-45b5-8be5-8ff7ad5219a2;22;150;JPY;13 diff --git a/app/single-tenant/personal-space/demoapp/db/data/sap.capire.bookshop-Books_texts.csv b/app/single-tenant/personal-space/demoapp/db/data/sap.capire.bookshop-Books_texts.csv new file mode 100644 index 000000000..3a3465b28 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/db/data/sap.capire.bookshop-Books_texts.csv @@ -0,0 +1,5 @@ +ID_texts;ID;locale;title;descr +52eee553-266d-4fdd-a5ca-909910e76ae4;aeeda49f-72f2-4880-be27-a513b2e53040;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. +54e58142-f06e-49c1-a51d-138f86cea34e;aeeda49f-72f2-4880-be27-a513b2e53040;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. +bbbf8a88-797d-4790-af1c-1cc857718ee0;b0056977-4cf5-46a2-ab14-6409ee2e0df1;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 +a90d4378-1a3e-48e7-b60b-5670e78807e1;7756b725-cefc-43a2-a3c8-0c9104a349b8;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. diff --git a/app/single-tenant/personal-space/demoapp/db/data/sap.capire.bookshop-Genres.csv b/app/single-tenant/personal-space/demoapp/db/data/sap.capire.bookshop-Genres.csv new file mode 100644 index 000000000..1ea3793bb --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/db/data/sap.capire.bookshop-Genres.csv @@ -0,0 +1,16 @@ +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;21;Autobiography +23;20;Essay +24;20;Speech diff --git a/app/single-tenant/personal-space/demoapp/db/package-lock.json b/app/single-tenant/personal-space/demoapp/db/package-lock.json new file mode 100644 index 000000000..37a8a994c --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/db/package-lock.json @@ -0,0 +1,325 @@ +{ + "name": "deploy", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "deploy", + "dependencies": { + "@sap/hdi-deploy": "^5", + "hdb": "^0" + }, + "engines": { + "node": "^20" + } + }, + "node_modules/@sap/hdi-deploy": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@sap/hdi-deploy/-/hdi-deploy-5.2.2.tgz", + "integrity": "sha512-4QoWgDfT/Bx6CbjRp9vP4+iPtcJpBfXZhaNamQXif4dA+fyraAvO3KALGgTFZEYbU1Aw1D3O+BGIpWZCzTua2A==", + "hasInstallScript": true, + "hasShrinkwrap": true, + "license": "See LICENSE file", + "dependencies": { + "@sap/hdi": "4.5.2", + "@sap/xsenv": "5.2.0", + "async": "3.2.6", + "dotenv": "16.4.5", + "handlebars": "4.7.8", + "micromatch": "4.0.8" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0" + }, + "peerDependencies": { + "@sap/hana-client": "^2 >= 2.6", + "hdb": "^0" + }, + "peerDependenciesMeta": { + "@sap/hana-client": { + "optional": true + }, + "hdb": { + "optional": true + } + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/hana-client": { + "version": "2.20.23", + "hasInstallScript": true, + "optional": true, + "peer": true, + "dependencies": { + "debug": "3.1.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/hdi": { + "version": "4.5.2", + "dependencies": { + "async": "3.2.3" + }, + "engines": { + "node": ">=12 <=20" + }, + "peerDependencies": { + "@sap/hana-client": "^2 >= 2.5", + "hdb": "^0" + }, + "peerDependenciesMeta": { + "@sap/hana-client": { + "optional": true + }, + "hdb": { + "optional": true + } + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/hdi/node_modules/async": { + "version": "3.2.3" + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv": { + "version": "5.2.0", + "dependencies": { + "debug": "4.3.5", + "node-cache": "^5.1.0", + "verror": "1.10.1" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/debug": { + "version": "4.3.5", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/ms": { + "version": "2.1.2" + }, + "node_modules/@sap/hdi-deploy/node_modules/assert-plus": { + "version": "1.0.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/async": { + "version": "3.2.6" + }, + "node_modules/@sap/hdi-deploy/node_modules/braces": { + "version": "3.0.3", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/clone": { + "version": "2.1.2", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/core-util-is": { + "version": "1.0.2" + }, + "node_modules/@sap/hdi-deploy/node_modules/debug": { + "version": "3.1.0", + "optional": true, + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/dotenv": { + "version": "16.4.5", + "engines": { + "node": ">=12" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/extsprintf": { + "version": "1.4.1", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/@sap/hdi-deploy/node_modules/fill-range": { + "version": "7.1.1", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/handlebars": { + "version": "4.7.8", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/hdb": { + "version": "0.19.9", + "optional": true, + "peer": true, + "dependencies": { + "iconv-lite": "^0.4.18" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/iconv-lite": { + "version": "0.4.24", + "optional": true, + "peer": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/is-number": { + "version": "7.0.0", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/micromatch": { + "version": "4.0.8", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/minimist": { + "version": "1.2.8" + }, + "node_modules/@sap/hdi-deploy/node_modules/ms": { + "version": "2.0.0", + "optional": true, + "peer": true + }, + "node_modules/@sap/hdi-deploy/node_modules/neo-async": { + "version": "2.6.2" + }, + "node_modules/@sap/hdi-deploy/node_modules/node-cache": { + "version": "5.1.2", + "dependencies": { + "clone": "2.x" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/picomatch": { + "version": "2.3.1", + "engines": { + "node": ">=8.6" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/safer-buffer": { + "version": "2.1.2", + "optional": true, + "peer": true + }, + "node_modules/@sap/hdi-deploy/node_modules/source-map": { + "version": "0.6.1", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/to-regex-range": { + "version": "5.0.1", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/uglify-js": { + "version": "3.19.2", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/verror": { + "version": "1.10.1", + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/@sap/hdi-deploy/node_modules/wordwrap": { + "version": "1.0.0" + }, + "node_modules/hdb": { + "version": "0.19.9", + "resolved": "https://registry.npmjs.org/hdb/-/hdb-0.19.9.tgz", + "integrity": "sha512-YtmP4mUmPLANF/HTdvIDIwELYl3H1ld21qRHYfcCW2ol1MXEnze504LoDXxBIuZD7i9LXCT62Bp0Ey5kSRocsg==", + "license": "Apache-2.0", + "dependencies": { + "iconv-lite": "^0.4.18" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + } + } + } + \ No newline at end of file diff --git a/app/single-tenant/personal-space/demoapp/db/package.json b/app/single-tenant/personal-space/demoapp/db/package.json new file mode 100644 index 000000000..62ba6ff18 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/db/package.json @@ -0,0 +1,15 @@ +{ + "name": "deploy", + "dependencies": { + "hdb": "^0", + "@sap/hdi-deploy": "^5" + }, + "engines": { + "node": "^20" + }, + "scripts": { + "start": "node node_modules/@sap/hdi-deploy/deploy.js --use-hdb", + "build": "npm ci && npx cds build .. --for hana --production" + } + } + \ No newline at end of file diff --git a/app/single-tenant/personal-space/demoapp/db/pom.xml b/app/single-tenant/personal-space/demoapp/db/pom.xml new file mode 100644 index 000000000..7a74659e1 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/db/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + + demoapp-parent + customer + ${revision} + + + db + + + + + com.sap.cds + sdm + 1.0.0-RC1 + + + + + + + com.sap.cds + cds-maven-plugin + ${cds.services.version} + + + cds.clean + + clean + + + + cds.resolve + + resolve + + + + + + + + diff --git a/app/single-tenant/personal-space/demoapp/db/schema.cds b/app/single-tenant/personal-space/demoapp/db/schema.cds new file mode 100644 index 000000000..5837c3e7c --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/db/schema.cds @@ -0,0 +1,98 @@ +using { +Currency, +managed, +cuid, +sap.common.CodeList +} from '@sap/cds/common'; + +namespace sap.capire.bookshop; + +entity Books : managed, cuid { +@mandatory title : localized String(111); +descr : localized String(1111); +@mandatory author : Association to Authors; +genre : Association to Genres; +stock : Integer; +price : Decimal; +currency : Currency; +image : LargeBinary @Core.MediaType: 'image/png'; +virtual isAttachmentsUploadable : Boolean; +virtual isReferencesUploadable : Boolean; + +// top-level chapters composition (root of the nested hierarchy) +cHapters : Composition of many Chapters on cHapters.book = $self; + +// top-level pages composition (same pattern as chapters) +pages : Composition of many Pages on pages.book = $self; + +// keep any other fields as before +} + +entity Authors : managed, cuid { +@mandatory 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 : CodeList { +key ID : Integer; +parent : Association to Genres; +children : Composition of many Genres +on children.parent = $self; +} + +// --- Nested composition entities to emulate deep structure --- + +// entity Chapters : cuid, managed { +// title : String(255); + +// // backlink to parent Book +// book : Association to Books; + +// // each chapter has many sections +// sections : Composition of many Sections on sections.chapter = $self; +// } + +entity Chapters : cuid, managed { + book : Association to Books; + title : String @title: 'Chapter Title'; + description : String; + url : String; + chapterType : String @title: 'Chapter Type'; +} + +/** Adding {Notebooks,Writers} for user service */ +entity Notebooks : managed, cuid { + @mandatory title : localized String(111); + descr : localized String(1111); + @mandatory writer : Association to Writers; + stock : Integer; + price : Decimal; + currency : Currency; + image : LargeBinary @Core.MediaType: 'image/png'; + virtual isAttachmentsUploadable : Boolean; +} + +entity Pages : cuid, managed { + book : Association to Books; + title : String @title: 'Page Title'; + description : String; + url : String; + pageType : String @title: 'Page Type'; +} + +entity Writers : managed, cuid { + @mandatory name : String(111); + dateOfBirth : Date; + dateOfDeath : Date; + placeOfBirth : String; + placeOfDeath : String; + notebooks : Association to many Notebooks + on notebooks.writer = $self; +} + diff --git a/app/single-tenant/personal-space/demoapp/mta.yaml b/app/single-tenant/personal-space/demoapp/mta.yaml new file mode 100644 index 000000000..273d3a803 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/mta.yaml @@ -0,0 +1,110 @@ +_schema-version: '2.1' +ID: demoappjava +version: 1.0.0 +description: "demoappjava CAP Java Project with UI" +parameters: + enable-parallel-deployments: true +modules: +# --------------------- SERVER MODULE ------------------------ + - name: demoappjava-srv +# ------------------------------------------------------------ + type: java + path: srv + parameters: + memory: 1024M + disk-quota: 512M + buildpack: sap_java_buildpack_jakarta + properties: + SPRING_PROFILES_ACTIVE: cloud,sandbox + JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jre.SAPMachineJRE']" + JBP_CONFIG_SAP_MACHINE_JRE: '{ version: 21.+ }' + REPOSITORY_ID: __REPOSITORY_ID__ # Placeholder for REPOSITORY_ID + INCOMING_REQUEST_TIMEOUT: 3600000 + INCOMING_SESSION_TIMEOUT: 3600000 + INCOMING_CONNECTION_TIMEOUT: 3600000 + build-parameters: + builder: custom + commands: + - mvn clean package -DskipTests=true + build-result: target/*-exec.jar + requires: + - name: demoappjava-hdi-container + - name: demoappjava-public-uaa + - name: cf-logging + - name: sdm + provides: + - name: srv-api + properties: + srv-url: '${default-url}' +# --------------------- DB MODULE --------------------------- + - name: demoappjava-db +# ----------------------------------------------------------- + type: hdb + path: db + parameters: + buildpack: nodejs_buildpack + build-parameters: + builder: custom + commands: + - npm run build + requires: + - name: demoappjava-srv + requires: + - name: demoappjava-hdi-container +# --------------------- APPROUTER MODULE --------------------- + - name: demoappjava-app +# ------------------------------------------------------------ + type: approuter.nodejs + path: app + parameters: + memory: 256M + disk-quota: 512M + properties: + INCOMING_REQUEST_TIMEOUT: 3600000 + INCOMING_SESSION_TIMEOUT: 3600000 + INCOMING_CONNECTION_TIMEOUT: 3600000 + requires: + - name: srv-api + group: destinations + properties: + name: backend + url: ~{srv-url} + forwardAuthToken: true + strictSSL: true + timeout: 3600000 + - name: demoappjava-public-uaa + provides: + - name: app-api + properties: + app-url: '${default-url}' +# --------------------- RESOURCES --------------------- +resources: +# ----------------------------------------------------- + - name: demoappjava-public-uaa + type: org.cloudfoundry.managed-service + parameters: + service: xsuaa + service-plan: application + path: ./xs-security.json + config: # override xsappname as it needs to be unique + xsappname: demoappjava-${org}-${space} + oauth2-configuration: + redirect-uris: + - ~{app-api/app-url}/** + requires: + - name: app-api + - name: demoappjava-hdi-container + type: org.cloudfoundry.managed-service + parameters: + service: hana + service-plan: hdi-shared + - name: cf-logging + type: org.cloudfoundry.managed-service + parameters: + service: application-logs + service-plan: lite + - name: sdm + type: org.cloudfoundry.managed-service + parameters: + service: sdm + service-plan: standard diff --git a/app/single-tenant/personal-space/demoapp/package-lock.json b/app/single-tenant/personal-space/demoapp/package-lock.json new file mode 100644 index 000000000..307829033 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "demoapp-cds", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "demoapp-cds", + "version": "1.0.0", + "license": "ISC" + } + } +} \ No newline at end of file diff --git a/app/single-tenant/personal-space/demoapp/package.json b/app/single-tenant/personal-space/demoapp/package.json new file mode 100644 index 000000000..89b583346 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/package.json @@ -0,0 +1,11 @@ +{ + "name": "demoapp-cds", + "version": "1.0.0", + "description": "Generated by cds-services-archetype", + "license": "ISC", + "repository": "", + "sapux": [ + "app/admin-books", + "app/browse" + ] +} diff --git a/app/single-tenant/personal-space/demoapp/pom.xml b/app/single-tenant/personal-space/demoapp/pom.xml new file mode 100644 index 000000000..272527e30 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/pom.xml @@ -0,0 +1,149 @@ + + + 4.0.0 + + customer + demoapp-parent + ${revision} + pom + + demoapp parent + + + + 1.0.0-SNAPSHOT + + + 21 + 4.1.1 + 3.3.1 + 8.0.2 + + https://nodejs.org/dist/ + UTF-8 + + + + srv + + + + + + + com.sap.cds + cds-services-bom + ${cds.services.version} + pom + import + + + + + org.springframework.boot + spring-boot-dependencies + ${spring.boot.version} + pom + import + + + + + + + github-snapshot + https://maven.pkg.github.com/cap-java/sdm + + true + + + true + + + + + + + + + maven-compiler-plugin + 3.13.0 + + ${jdk.version} + UTF-8 + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + true + + + + + + maven-surefire-plugin + 3.3.0 + + + + + org.codehaus.mojo + flatten-maven-plugin + 1.6.0 + + true + resolveCiFriendliesOnly + + + + flatten + process-resources + + flatten + + + + flatten.clean + clean + + clean + + + + + + + + maven-enforcer-plugin + 3.5.0 + + + Project Structure Checks + + enforce + + + + + 3.5.0 + + + ${jdk.version} + + + + true + + + + + + + diff --git a/app/single-tenant/personal-space/demoapp/srv/admin-service.cds b/app/single-tenant/personal-space/demoapp/srv/admin-service.cds new file mode 100644 index 000000000..e5dfbb1b7 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/srv/admin-service.cds @@ -0,0 +1,321 @@ +using { sap.capire.bookshop as my } from '../db/schema'; +service AdminService @(requires: ['admin','system-user']) { + + entity Books as projection on my.Books; + entity Authors as projection on my.Authors; + entity Chapters as projection on my.Chapters; + entity Pages as projection on my.Pages; + + // Define a return type for the action result + type MoveAttachmentsResult { + failedObjectIds : array of String; + } + + entity Books.attachments as projection on my.Books.attachments + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + annotate AdminService.Books.attachments with @( + Capabilities: {InsertRestrictions: {Insertable: up_.isAttachmentsUploadable}} + ); + + entity Books.references as projection on my.Books.references + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + annotate AdminService.Books.references with @( + Capabilities: {InsertRestrictions: {Insertable: up_.isReferencesUploadable}} + ); + + entity Books.footnotes as projection on my.Books.footnotes + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + entity Pages.attachments as projection on my.Pages.attachments + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + entity Pages.references as projection on my.Pages.references + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + // Chapters projections + entity Chapters.attachments as projection on my.Chapters.attachments + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + entity Chapters.references as projection on my.Chapters.references + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + entity Chapters.footnotes as projection on my.Chapters.footnotes + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; + + // Side effects on parent entities: structural changes (add/delete) on attachment + // navigation collections trigger a re-read of the uploadable flag on the parent. + annotate AdminService.Books with @( + Common.SideEffects #sdmAttachmentsUploadable: { + SourceEntities: ['attachments'], + TargetProperties: ['isAttachmentsUploadable'] + }, + Common.SideEffects #sdmReferencesUploadable: { + SourceEntities: ['references'], + TargetProperties: ['isReferencesUploadable'] + } + ); + + // Pages footnotes projection + entity Pages.footnotes as projection on my.Pages.footnotes + actions { + @(Common.SideEffects : {TargetEntities: ['']},) + action createAttachmentInActive(in:many $self); + @(Common.SideEffects : {TargetEntities: ['']},) + action copyAttachments(in:many $self, up__ID:String, objectIds:String); + // moveAttachments action signature + @(Common.SideEffects : {TargetEntities: ['']}) + action moveAttachments( + in: many $self, + up__ID: String, + sourceFolderId: String, + objectIds: String, + targetFacet: String, + sourceFacet: String, // Optional: if not provided, no source cleanup + ) returns MoveAttachmentsResult; // Return structured type + + @(Common.SideEffects : {TargetEntities: ['up_']},) + action createLink( + in:many $self, + @mandatory @Common.Label:'Name' name: String @UI.Placeholder: 'Enter a name for the link', + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + + action editLink( + @mandatory @assert.format:'^(https?:\/\/)(([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}|localhost)(:\d{2,5})?(\/[^\s]*)?$' @Common.Label:'URL' url: String @UI.Placeholder: 'Example: https://www.example.com' + ); + action openAttachment() returns String; + action changelog() returns String; + action downloadSelectedAttachments(ids: String) returns String; + }; +} diff --git a/app/single-tenant/personal-space/demoapp/srv/attachment-extension.cds b/app/single-tenant/personal-space/demoapp/srv/attachment-extension.cds new file mode 100644 index 000000000..6ec38cdcc --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/srv/attachment-extension.cds @@ -0,0 +1,168 @@ +using {sap.capire.bookshop.Books, sap.capire.bookshop.Chapters, sap.capire.bookshop.Pages, sap.capire.bookshop.Notebooks} from '../db/schema'; +using {sap.attachments.Attachments, sap.attachments.StatusCode} from 'com.sap.cds/sdm'; +using {sap,managed,sap.common.CodeList} from '@sap/cds/common'; + +// keep the original shallow attachments on Books +extend entity Books with { + attachments : Composition of many Attachments @SDM.Attachments:{maxCount: 4, maxCountError:'Only 4 attachments allowed.'}; + references : Composition of many Attachments @SDM.Attachments:{maxCount: 5, maxCountError:'Only 5 attachments allowed.'}; + footnotes : Composition of many Attachments; +} + +extend entity Notebooks with { + attachments : Composition of many Attachments @SDM.Attachments:{maxCount: 4, maxCountError:'Only 4 attachments allowed.'}; +} + +extend entity Chapters with { + attachments: Composition of many Attachments; + references: Composition of many Attachments; + footnotes: Composition of many Attachments; +} + +extend entity Pages with { + attachments: Composition of many Attachments; + references: Composition of many Attachments; + footnotes: Composition of many Attachments; +} + + + +entity Statuses @cds.autoexpose @readonly { + key code : StatusCode; + text : localized String(255); +} + +extend Attachments with { + statusText : Association to Statuses on statusText.code = $self.status; +} + +annotate Books.attachments with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + + + +annotate Books.references with { + content @Validation.Maximum : '30MB'; + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate Chapters.attachments with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate Chapters.references with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate Pages.attachments with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate Pages.references with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate Chapters.footnotes with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + +annotate Pages.footnotes with { + status @( + Common.Text: { + $value: ![statusText.text], + ![@UI.TextArrangement]: #TextOnly + }, + ValueList: { entity: 'Statuses' }, + sap.value.list: 'fixed-values' + ); +} + + + +extend Attachments with { + customProperty1 : WDIRS_CodeList_TYPE + @SDM.Attachments.AdditionalProperty: { + name: 'Working:DocumentInfoRecordString' + } + @(title: 'DocumentInfoRecordString'); + customProperty2 : Integer + @SDM.Attachments.AdditionalProperty: { + name: 'Working:DocumentInfoRecordInt' + }; + customProperty3 : String + @SDM.Attachments.AdditionalProperty: { + name: 'abc:myId1' + } + @(title: 'id1'); + customProperty4 : String + @SDM.Attachments.AdditionalProperty: { + name: 'abc:myId2' + } + @(title: 'id2'); + customProperty5 : DateTime + @SDM.Attachments.AdditionalProperty: { + name: 'Working:DocumentInfoRecordDate' + } + @(title: 'DocumentInfoRecordDate'); + customProperty6 : Boolean + @SDM.Attachments.AdditionalProperty: { + name: 'Working:DocumentInfoRecordBoolean' + } + @(title: 'DocumentInfoRecordBoolean'); +} + +entity WDIRSCodeList : CodeList { + key code : String(30) @Common.Text : name @Common.TextArrangement: #TextFirst; +}; + +type WDIRS_CodeList_TYPE : Association to one WDIRSCodeList; diff --git a/app/single-tenant/personal-space/demoapp/srv/cat-service.cds b/app/single-tenant/personal-space/demoapp/srv/cat-service.cds new file mode 100644 index 000000000..1d2cbbab8 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/srv/cat-service.cds @@ -0,0 +1,34 @@ +using {sap.capire.bookshop as my} from '../db/schema'; + +service CatalogService { + + /** 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 + }; + + action submitOrder(book : Books:ID, quantity : Integer) returns { + stock : Integer + }; + + event OrderedBook : { + book : Books:ID; + quantity : Integer; + buyer : String + }; +} diff --git a/app/single-tenant/personal-space/demoapp/srv/pom.xml b/app/single-tenant/personal-space/demoapp/srv/pom.xml new file mode 100644 index 000000000..1a18bebd8 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/srv/pom.xml @@ -0,0 +1,170 @@ + + 4.0.0 + + + demoapp-parent + customer + ${revision} + + + demoapp + jar + + demoapp + + + + + + com.sap.cds + sdm + 1.0.0-RC1 + + + + + + com.sap.cds + cds-starter-spring-boot + + + + + com.sap.cds + cds-adapter-odata-v4 + runtime + + + + org.springframework.boot + spring-boot-devtools + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + com.h2database + h2 + runtime + + + + org.springframework.boot + spring-boot-starter-security + + + + + ${project.artifactId} + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + false + + + + repackage + + repackage + + + exec + + + + + + + + com.sap.cds + cds-maven-plugin + ${cds.services.version} + + + cds.clean + + clean + + + + + cds.install-node + + install-node + + + ${cdsdk-global} + + + + + cds.install-cdsdk + + install-cdsdk + + + ${cdsdk-global} + + + + + cds.resolve + + resolve + + + + + cds.build + + cds + + + + build --for java + deploy --to h2 --dry > "${project.basedir}/src/main/resources/schema-h2.sql" + + + + + + cds.generate + + generate + + + cds.gen + true + true + + + + + + + + + + + cdsdk-global + + + env.CDSDK_GLOBAL + true + + + + true + + + + diff --git a/app/single-tenant/personal-space/demoapp/srv/src/main/java/customer/demoapp/Application.java b/app/single-tenant/personal-space/demoapp/srv/src/main/java/customer/demoapp/Application.java new file mode 100644 index 000000000..35ca27fdf --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/srv/src/main/java/customer/demoapp/Application.java @@ -0,0 +1,13 @@ +package customer.demoapp; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/app/single-tenant/personal-space/demoapp/srv/src/main/java/customer/demoapp/handlers/AdminServiceHandler.java b/app/single-tenant/personal-space/demoapp/srv/src/main/java/customer/demoapp/handlers/AdminServiceHandler.java new file mode 100644 index 000000000..4281f4957 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/srv/src/main/java/customer/demoapp/handlers/AdminServiceHandler.java @@ -0,0 +1,230 @@ +package customer.demoapp.handlers; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import com.sap.cds.ql.Insert; +import com.sap.cds.ql.cqn.CqnAnalyzer; +import com.sap.cds.ql.cqn.CqnComparisonPredicate; +import com.sap.cds.ql.cqn.CqnConnectivePredicate; +import com.sap.cds.ql.cqn.CqnElementRef; +import com.sap.cds.ql.cqn.CqnLiteral; +import com.sap.cds.ql.cqn.CqnPredicate; +import com.sap.cds.ql.cqn.CqnReference; +import com.sap.cds.ql.cqn.CqnSelect; +import com.sap.cds.ql.cqn.CqnStructuredTypeRef; +import com.sap.cds.services.EventContext; +import com.sap.cds.services.cds.ApplicationService; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.On; +import com.sap.cds.services.handler.annotations.ServiceName; + +import java.util.List; + +import cds.gen.adminservice.AdminService_; +import cds.gen.adminservice.BooksAttachments_; + +/** + * Handler for AdminService operations including creating attachments in active entity state. + */ +@Component +@ServiceName(AdminService_.CDS_NAME) +public class AdminServiceHandler implements EventHandler { + + private static final Logger logger = LoggerFactory.getLogger(AdminServiceHandler.class); + + @Autowired + @Qualifier("AdminService") + private ApplicationService adminService; + + /** + * Handler for createAttachmentInActive action. + */ + @On(event = "createAttachmentInActive") + public void createAttachmentInActive(EventContext context) { + String targetEntity = context.getTarget().getQualifiedName(); + logger.info("=== createAttachmentInActive triggered for entity: {} ===", targetEntity); + + // Guard: When CAP invokes this during draft activation (edit+save), + // the "in" parameter contains existing attachment rows. + // A user-initiated button click sends "in" as null/empty (RequiresSelection: false). + // Skip execution if "in" has items — that means it's a framework save, not a user click. + Object inParam = context.get("in"); + if (inParam instanceof List && !((List) inParam).isEmpty()) { + logger.info("Skipping createAttachmentInActive — triggered by framework save (in has {} items), not user click", ((List) inParam).size()); + context.setCompleted(); + return; + } + + try { + // Extract the parent entity ID from CQN + CqnSelect cqn = (CqnSelect) context.get("cqn"); + CqnAnalyzer analyzer = CqnAnalyzer.create(context.getModel()); + Map rootKeys = analyzer.analyze(cqn).rootKeys(); + logger.info("Root keys: {}", rootKeys); + + // Extract the immediate parent ID. + // For non-nested entities (e.g., Books.attachments), rootKeys has {up__ID: bookID}. + // For nested entities (e.g., Chapters.attachments via composition path + // Books(bookID)/chapters(chapterID)/attachments), rootKeys only has {ID: bookID} + // and the Chapter ID is in the penultimate CQN path segment's filter. + String parentId = extractParentId(cqn, rootKeys); + + if (parentId == null || parentId.isEmpty()) { + logger.error("Could not extract parent ID from CQN. Root keys: {}", rootKeys); + context.setCompleted(); + throw new RuntimeException("Parent entity ID is required to create attachment."); + } + + logger.info("Creating attachment for parent ID: {} in facet: {}", parentId, targetEntity); + + // Create attachment with unique filename (timestamp prevents any duplicate issues) + String attachmentId = createAttachmentWithContent(parentId, targetEntity); + logger.info("Attachment created successfully with ID: {}", attachmentId); + + context.setCompleted(); + + } catch (Exception e) { + logger.error("Failed to create attachment: {}", e.getMessage(), e); + context.setCompleted(); + throw new RuntimeException("Failed to create attachment: " + e.getMessage(), e); + } + } + + /** + * Creates an attachment record with content in the active entity state. + * Uses a timestamp-based unique filename to prevent duplicate issues. + */ + private String createAttachmentWithContent(String parentId, String targetEntity) throws IOException { + String attachmentId = UUID.randomUUID().toString(); + + // Use timestamp in filename to guarantee uniqueness + String timestamp = DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss-SSS") + .withZone(ZoneId.systemDefault()) + .format(Instant.now()); + String fileName = "attachment-" + timestamp + ".txt"; + + String sampleContent = "Sample Attachment\n" + + "Created: " + Instant.now() + "\n" + + "Parent ID: " + parentId + "\n" + + "Facet: " + targetEntity + "\n" + + "Attachment ID: " + attachmentId; + + InputStream contentStream = new ByteArrayInputStream(sampleContent.getBytes(StandardCharsets.UTF_8)); + + Map attachmentData = new HashMap<>(); + attachmentData.put("ID", attachmentId); + attachmentData.put("up__ID", parentId); + attachmentData.put("fileName", fileName); + attachmentData.put("mimeType", "text/plain"); + attachmentData.put("note", "Created programmatically in active entity"); + attachmentData.put("content", contentStream); + + // Determine which entity to insert into based on the target + // The target will be like "AdminService.Books.attachments" or "AdminService.Chapters.attachments" etc. + String insertTarget = targetEntity; + logger.info("Inserting attachment into: {}", insertTarget); + + Insert insert = Insert.into(insertTarget).entry(attachmentData); + adminService.run(insert); + + return attachmentId; + } + + /** + * Extracts the immediate parent entity's ID from the CQN. + * + * For non-nested entities (e.g., Books.attachments): + * CQN: SELECT from AdminService.Books.attachments WHERE up__ID = 'bookID' + * rootKeys = {up__ID: bookID} → up__ID found directly. + * + * For nested entities (e.g., Chapters.attachments via composition path): + * CQN: SELECT from AdminService.Books[ID='bookID'].chapters[ID='chapterID'].attachments + * rootKeys = {ID: bookID} → up__ID NOT found. + * Fix: traverse CQN path segments and extract ID from the penultimate segment + * (which represents the immediate parent entity, e.g., chapters[ID='chapterID']). + */ + private String extractParentId(CqnSelect cqn, Map rootKeys) { + // Case 1: Direct entity set — rootKeys has up__ID + Object upId = rootKeys.get("up__ID"); + if (upId != null) { + logger.info("Found up__ID in rootKeys: {}", upId); + return upId.toString(); + } + + // Case 2: Nested composition path — traverse CQN ref segments + try { + if (cqn.from().isRef()) { + CqnStructuredTypeRef ref = cqn.from().asRef(); + List segments = ref.segments(); + logger.info("CQN path has {} segments", segments.size()); + + if (segments.size() >= 2) { + // Penultimate segment is the immediate parent (e.g., "chapters") + CqnReference.Segment parentSegment = segments.get(segments.size() - 2); + logger.info("Parent segment: {}, has filter: {}", + parentSegment.id(), parentSegment.filter().isPresent()); + + if (parentSegment.filter().isPresent()) { + String parentId = extractIdFromPredicate(parentSegment.filter().get()); + if (parentId != null) { + logger.info("Extracted parent ID from CQN segment '{}': {}", + parentSegment.id(), parentId); + return parentId; + } + } + } + } + } catch (Exception e) { + logger.warn("Could not extract parent ID from CQN path segments: {}", e.getMessage()); + } + + // Fallback: use ID from rootKeys (correct for non-nested, wrong for nested) + Object id = rootKeys.get("ID"); + if (id != null) { + logger.warn("Using fallback ID from rootKeys (may be wrong for nested entities): {}", id); + return id.toString(); + } + + return null; + } + + /** + * Recursively extracts the "ID" value from a CQN predicate. + * Handles simple comparisons (ID = 'value') and conjunctions (ID = 'value' AND IsActiveEntity = true). + */ + private String extractIdFromPredicate(CqnPredicate predicate) { + if (predicate instanceof CqnComparisonPredicate) { + CqnComparisonPredicate comp = (CqnComparisonPredicate) predicate; + if (comp.left() instanceof CqnElementRef && comp.right() instanceof CqnLiteral) { + String fieldName = ((CqnElementRef) comp.left()).lastSegment(); + if ("ID".equals(fieldName)) { + return ((CqnLiteral) comp.right()).value().toString(); + } + } + } else if (predicate instanceof CqnConnectivePredicate) { + // Conjunction (AND) or disjunction (OR) — check each child + for (CqnPredicate child : ((CqnConnectivePredicate) predicate).predicates()) { + String id = extractIdFromPredicate(child); + if (id != null) { + return id; + } + } + } + return null; + } +} diff --git a/app/single-tenant/personal-space/demoapp/srv/src/main/java/customer/demoapp/handlers/CatalogServiceHandler.java b/app/single-tenant/personal-space/demoapp/srv/src/main/java/customer/demoapp/handlers/CatalogServiceHandler.java new file mode 100644 index 000000000..72f5d969b --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/srv/src/main/java/customer/demoapp/handlers/CatalogServiceHandler.java @@ -0,0 +1,63 @@ +package customer.demoapp.handlers; + +import java.util.stream.Stream; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.sap.cds.ql.Select; +import com.sap.cds.ql.Update; +import com.sap.cds.services.cds.CqnService; +import com.sap.cds.services.handler.EventHandler; +import com.sap.cds.services.handler.annotations.After; +import com.sap.cds.services.handler.annotations.On; +import com.sap.cds.services.handler.annotations.ServiceName; +import com.sap.cds.services.persistence.PersistenceService; + +import cds.gen.catalogservice.Books; +import cds.gen.catalogservice.Books_; +import cds.gen.catalogservice.CatalogService_; +import cds.gen.catalogservice.OrderedBook; +import cds.gen.catalogservice.OrderedBookContext; +import cds.gen.catalogservice.SubmitOrderContext; +import cds.gen.catalogservice.SubmitOrderContext.ReturnType; + +@Component +@ServiceName(CatalogService_.CDS_NAME) +public class CatalogServiceHandler implements EventHandler { + + @Autowired + private PersistenceService db; + + @On + public void submitOrder(SubmitOrderContext context) { + // decrease and update stock in database + db.run(Update.entity(Books_.class).byId(context.getBook()).set(b -> b.stock(), s -> s.minus(context.getQuantity()))); + + // read new stock from database + Books book = db.run(Select.from(Books_.class).where(b -> b.ID().eq(context.getBook()))).single(Books.class); + + // return new stock to client + ReturnType result = SubmitOrderContext.ReturnType.create(); + result.setStock(book.getStock()); + + OrderedBook orderedBook = OrderedBook.create(); + orderedBook.setBook(book.getId()); + orderedBook.setQuantity(context.getQuantity()); + orderedBook.setBuyer(context.getUserInfo().getName()); + + OrderedBookContext orderedBookEvent = OrderedBookContext.create(); + orderedBookEvent.setData(orderedBook); + context.getService().emit(orderedBookEvent); + + context.setResult(result); + } + + @After(event = CqnService.EVENT_READ) + public void discountBooks(Stream books) { + books.filter(b -> b.getTitle() != null && b.getStock() != null) + .filter(b -> b.getStock() > 200) + .forEach(b -> b.setTitle(b.getTitle() + " (discounted)")); + } + +} \ No newline at end of file diff --git a/app/single-tenant/personal-space/demoapp/srv/src/main/resources/application.yaml b/app/single-tenant/personal-space/demoapp/srv/src/main/resources/application.yaml new file mode 100644 index 000000000..a95dc604c --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/srv/src/main/resources/application.yaml @@ -0,0 +1,11 @@ +--- +spring: + config: + activate: + on-profile: default + sql: + init: + schema-locations: classpath:schema-h2.sql + data-source: + auto-config: + enabled: false \ No newline at end of file diff --git a/app/single-tenant/personal-space/demoapp/srv/src/main/resources/messages.properties b/app/single-tenant/personal-space/demoapp/srv/src/main/resources/messages.properties new file mode 100644 index 000000000..8e99a85d0 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/srv/src/main/resources/messages.properties @@ -0,0 +1 @@ +SDM.Attachments.maxCountError = Maximum number of attachments reached in English diff --git a/app/single-tenant/personal-space/demoapp/srv/src/test/java/customer/demoapp/handlers/CatalogServiceHandlerTest.java b/app/single-tenant/personal-space/demoapp/srv/src/test/java/customer/demoapp/handlers/CatalogServiceHandlerTest.java new file mode 100644 index 000000000..77d4d5509 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/srv/src/test/java/customer/demoapp/handlers/CatalogServiceHandlerTest.java @@ -0,0 +1,42 @@ +package customer.demoapp.handlers; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.stream.Stream; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import cds.gen.catalogservice.Books; + +class CatalogServiceHandlerTest { + + private CatalogServiceHandler handler = new CatalogServiceHandler(); + private Books book = Books.create(); + + @BeforeEach + public void prepareBook() { + book.setTitle("title"); + } + + @Test + void testDiscount() { + book.setStock(500); + handler.discountBooks(Stream.of(book)); + assertEquals("title (discounted)", book.getTitle()); + } + + @Test + void testNoDiscount() { + book.setStock(100); + handler.discountBooks(Stream.of(book)); + assertEquals("title", book.getTitle()); + } + + @Test + void testNoStockAvailable() { + handler.discountBooks(Stream.of(book)); + assertEquals("title", book.getTitle()); + } + +} diff --git a/app/single-tenant/personal-space/demoapp/srv/user-service.cds b/app/single-tenant/personal-space/demoapp/srv/user-service.cds new file mode 100644 index 000000000..de6444756 --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/srv/user-service.cds @@ -0,0 +1,10 @@ +using {sap.capire.bookshop as my} from '../db/schema'; + +service UserService @(requires: [ + 'admin', + 'system-user' +]) { + @odata.draft.enabled + entity Notebooks as projection on my.Notebooks; + entity Writers as projection on my.Writers; +} diff --git a/app/single-tenant/personal-space/demoapp/xs-security.json b/app/single-tenant/personal-space/demoapp/xs-security.json new file mode 100644 index 000000000..941dd117b --- /dev/null +++ b/app/single-tenant/personal-space/demoapp/xs-security.json @@ -0,0 +1,18 @@ +{ "xsappname": "demoappjava-${org}-${space}", + "tenant-mode": "dedicated", + "scopes": [ + { + "name": "$XSAPPNAME.admin", + "description": "admin" + } + ], + "role-templates": [ + { + "name": "admin", + "description": "generated", + "scope-references": [ + "$XSAPPNAME.admin" + ] + } + ] +} From e4a3239f347b0d6d8fbda9920f7f9d5ff4159f4f Mon Sep 17 00:00:00 2001 From: "Yashmeet ." Date: Thu, 4 Jun 2026 17:32:25 +0530 Subject: [PATCH 2/8] remove .gitignore from leading apps and add mta.yaml back --- .../cloud-cap-samples-java/.gitignore | 38 ---- .../cloud-cap-samples-java/mta.yaml | 170 ++++++++++++++++++ .../cloud-cap-samples-java/.gitignore | 38 ---- .../cloud-cap-samples-java/mta.yaml | 170 ++++++++++++++++++ .../central-space/demoapp/.gitignore | 31 ---- .../personal-space/demoapp/.gitignore | 31 ---- 6 files changed, 340 insertions(+), 138 deletions(-) delete mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/.gitignore create mode 100644 app/multi-tenant/central-space/cloud-cap-samples-java/mta.yaml delete mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/.gitignore create mode 100644 app/multi-tenant/personal-space/cloud-cap-samples-java/mta.yaml delete mode 100644 app/single-tenant/central-space/demoapp/.gitignore delete mode 100644 app/single-tenant/personal-space/demoapp/.gitignore diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/.gitignore b/app/multi-tenant/central-space/cloud-cap-samples-java/.gitignore deleted file mode 100644 index f9986b41c..000000000 --- a/app/multi-tenant/central-space/cloud-cap-samples-java/.gitignore +++ /dev/null @@ -1,38 +0,0 @@ -gen/ -edmx/ -schema-h2.sql -default-env.json -openapi.json -.env -.values.yaml - -bin/ -target/ -.java-version -.flattened-pom.xml -.classpath -.project -.settings -.vscode -.idea -*.iml - -node/ -node_modules/ - -.mta/ -*.mtar -mta.yaml - -*.log* -gc_history* -hs_err* -.DS_Store - -*.db -*.sqlite* - -.cdsrc-private.json - -/chart/ -.reloadtrigger diff --git a/app/multi-tenant/central-space/cloud-cap-samples-java/mta.yaml b/app/multi-tenant/central-space/cloud-cap-samples-java/mta.yaml new file mode 100644 index 000000000..1594e917e --- /dev/null +++ b/app/multi-tenant/central-space/cloud-cap-samples-java/mta.yaml @@ -0,0 +1,170 @@ +_schema-version: '2.1' +ID: bookshop-mt +version: 1.0.0 +description: "Multitenant Bookshop CAP Java Project with UI" +parameters: + enable-parallel-deployments: true +modules: +# --------------------- SERVER MODULE ------------------------ + - name: bookshop-mt-srv +# ------------------------------------------------------------ + type: java + path: srv + parameters: + memory: 1024M + disk-quota: 512M + buildpack: sap_java_buildpack_jakarta + properties: + SPRING_PROFILES_ACTIVE: cloud,sandbox + CDS_MULTITENANCY_APPUI_TENANTSEPARATOR: "-" + JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jre.SAPMachineJRE']" + JBP_CONFIG_SAP_MACHINE_JRE: '{ version: 21.+ }' + REPOSITORY_ID: __REPOSITORY_ID__ # Placeholder for REPOSITORY_ID + INCOMING_CONNECTION_TIMEOUT: 12000000 + INCOMING_REQUEST_TIMEOUT: 12000000 + timeout: 12000000 + build-parameters: + builder: custom + commands: + - mvn clean package -DskipTests=true + build-result: target/*-exec.jar + requires: + - name: bookshop-mt-service-manager + - name: bookshop-mt-uaa + - name: bookshop-mt-saas-registry + - name: sdm + - name: mtx-api + properties: + CDS_MULTITENANCY_SIDECAR_URL: ~{mtx-url} + - name: app-api + properties: + CDS_MULTITENANCY_APPUI_URL: ~{app-url} + - name: cf-logging + provides: + - name: srv-api + properties: + srv-url: '${default-url}' +# --------------------- SIDECAR MODULE ----------------------- + - name: bookshop-mt-sidecar +# ------------------------------------------------------------ + type: nodejs + path: mtx/sidecar + parameters: + memory: 256M + disk-quota: 1024M + build-parameters: + builder: custom + build-result: gen + commands: + - npm run build + requires: + - name: bookshop-mt-srv + requires: + - name: bookshop-mt-service-manager + - name: bookshop-mt-uaa + - name: cf-logging + - name: sdm + provides: + - name: mtx-api + properties: + mtx-url: ${default-url} + hooks: + - name: upgrade-all + type: task + phases: + - blue-green.application.before-start.idle + - deploy.application.before-start + parameters: + name: upgrade + memory: 512M + disk-quota: 768M + command: npx -p @sap/cds-mtx cds-mtx upgrade "*" +# --------------------- APPROUTER MODULE --------------------- + - name: bookshop-mt-app +# ------------------------------------------------------------ + type: approuter.nodejs + path: app + + parameters: + memory: 256M + disk-quota: 512M + keep-existing-routes: true + host: ${space}-1-multi-pgnaicm + routes: + # - route: playground-agri-com-de2-subscriber-${space}-pgcnaim.${default-domain} + - route: sdm-dev-consumer-eu12-6uxoiqfk-${default-uri} + - route: sdmgoogleworkspace-cpok9mi1-${default-uri} + properties: + TENANT_HOST_PATTERN: ^(.*)-${default-uri} # testing only, use custom domain with wildcard for production + INCOMING_CONNECTION_TIMEOUT: 1200000 + INCOMING_REQUEST_TIMEOUT: 1200000 + timeout: 1200000 + requires: + - name: srv-api + group: destinations + properties: + name: backend + url: ~{srv-url} + forwardAuthToken: true + strictSSL: true + timeout: 1200000 + - name: bookshop-mt-uaa + provides: + - name: app-api + properties: + app-url: '${default-url}' + app-domain: '${domain}' +# --------------------- RESOURCES --------------------- +resources: +# ----------------------------------------------------- + - name: bookshop-mt-uaa + type: org.cloudfoundry.managed-service + parameters: + service: xsuaa + service-plan: application + path: ./xs-security-mt.json + config: # override xsappname as it needs to be unique + xsappname: bookshop-mt-${org}-${space} + oauth2-configuration: + credential-types: + - binding-secret + - x509 + redirect-uris: + - https://*.~{app-api/app-domain}/** + requires: + - name: app-api + - name: bookshop-mt-service-manager + type: org.cloudfoundry.managed-service + parameters: + service: service-manager + service-plan: container + - name: bookshop-mt-saas-registry + type: org.cloudfoundry.managed-service + parameters: + service: saas-registry + service-plan: application + config: + appName: bookshop-mt-${org}-${space} # this is the text on the tile + xsappname: bookshop-mt-${org}-${space} # this is the value from xsuaa.parameters.config.xsappname + appUrls: + getDependencies: ~{srv-api/srv-url}/mt/v1.0/subscriptions/dependencies + onSubscription: ~{srv-api/srv-url}/mt/v1.0/subscriptions/tenants/{tenantId} + onSubscriptionAsync: true + onUnSubscriptionAsync: true + onUpdateDependenciesAsync: true + callbackTimeoutMillis: 3600000 + displayName: Multitenancy App ${space} + description: Multitenancy App test deployed using job + category: 'Category' + requires: + - name: srv-api + - name: cf-logging + type: org.cloudfoundry.managed-service + parameters: + service: application-logs + service-plan: lite + - name: sdm + type: org.cloudfoundry.managed-service + parameters: + service: sdm + service-plan: standard diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/.gitignore b/app/multi-tenant/personal-space/cloud-cap-samples-java/.gitignore deleted file mode 100644 index f9986b41c..000000000 --- a/app/multi-tenant/personal-space/cloud-cap-samples-java/.gitignore +++ /dev/null @@ -1,38 +0,0 @@ -gen/ -edmx/ -schema-h2.sql -default-env.json -openapi.json -.env -.values.yaml - -bin/ -target/ -.java-version -.flattened-pom.xml -.classpath -.project -.settings -.vscode -.idea -*.iml - -node/ -node_modules/ - -.mta/ -*.mtar -mta.yaml - -*.log* -gc_history* -hs_err* -.DS_Store - -*.db -*.sqlite* - -.cdsrc-private.json - -/chart/ -.reloadtrigger diff --git a/app/multi-tenant/personal-space/cloud-cap-samples-java/mta.yaml b/app/multi-tenant/personal-space/cloud-cap-samples-java/mta.yaml new file mode 100644 index 000000000..1594e917e --- /dev/null +++ b/app/multi-tenant/personal-space/cloud-cap-samples-java/mta.yaml @@ -0,0 +1,170 @@ +_schema-version: '2.1' +ID: bookshop-mt +version: 1.0.0 +description: "Multitenant Bookshop CAP Java Project with UI" +parameters: + enable-parallel-deployments: true +modules: +# --------------------- SERVER MODULE ------------------------ + - name: bookshop-mt-srv +# ------------------------------------------------------------ + type: java + path: srv + parameters: + memory: 1024M + disk-quota: 512M + buildpack: sap_java_buildpack_jakarta + properties: + SPRING_PROFILES_ACTIVE: cloud,sandbox + CDS_MULTITENANCY_APPUI_TENANTSEPARATOR: "-" + JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jre.SAPMachineJRE']" + JBP_CONFIG_SAP_MACHINE_JRE: '{ version: 21.+ }' + REPOSITORY_ID: __REPOSITORY_ID__ # Placeholder for REPOSITORY_ID + INCOMING_CONNECTION_TIMEOUT: 12000000 + INCOMING_REQUEST_TIMEOUT: 12000000 + timeout: 12000000 + build-parameters: + builder: custom + commands: + - mvn clean package -DskipTests=true + build-result: target/*-exec.jar + requires: + - name: bookshop-mt-service-manager + - name: bookshop-mt-uaa + - name: bookshop-mt-saas-registry + - name: sdm + - name: mtx-api + properties: + CDS_MULTITENANCY_SIDECAR_URL: ~{mtx-url} + - name: app-api + properties: + CDS_MULTITENANCY_APPUI_URL: ~{app-url} + - name: cf-logging + provides: + - name: srv-api + properties: + srv-url: '${default-url}' +# --------------------- SIDECAR MODULE ----------------------- + - name: bookshop-mt-sidecar +# ------------------------------------------------------------ + type: nodejs + path: mtx/sidecar + parameters: + memory: 256M + disk-quota: 1024M + build-parameters: + builder: custom + build-result: gen + commands: + - npm run build + requires: + - name: bookshop-mt-srv + requires: + - name: bookshop-mt-service-manager + - name: bookshop-mt-uaa + - name: cf-logging + - name: sdm + provides: + - name: mtx-api + properties: + mtx-url: ${default-url} + hooks: + - name: upgrade-all + type: task + phases: + - blue-green.application.before-start.idle + - deploy.application.before-start + parameters: + name: upgrade + memory: 512M + disk-quota: 768M + command: npx -p @sap/cds-mtx cds-mtx upgrade "*" +# --------------------- APPROUTER MODULE --------------------- + - name: bookshop-mt-app +# ------------------------------------------------------------ + type: approuter.nodejs + path: app + + parameters: + memory: 256M + disk-quota: 512M + keep-existing-routes: true + host: ${space}-1-multi-pgnaicm + routes: + # - route: playground-agri-com-de2-subscriber-${space}-pgcnaim.${default-domain} + - route: sdm-dev-consumer-eu12-6uxoiqfk-${default-uri} + - route: sdmgoogleworkspace-cpok9mi1-${default-uri} + properties: + TENANT_HOST_PATTERN: ^(.*)-${default-uri} # testing only, use custom domain with wildcard for production + INCOMING_CONNECTION_TIMEOUT: 1200000 + INCOMING_REQUEST_TIMEOUT: 1200000 + timeout: 1200000 + requires: + - name: srv-api + group: destinations + properties: + name: backend + url: ~{srv-url} + forwardAuthToken: true + strictSSL: true + timeout: 1200000 + - name: bookshop-mt-uaa + provides: + - name: app-api + properties: + app-url: '${default-url}' + app-domain: '${domain}' +# --------------------- RESOURCES --------------------- +resources: +# ----------------------------------------------------- + - name: bookshop-mt-uaa + type: org.cloudfoundry.managed-service + parameters: + service: xsuaa + service-plan: application + path: ./xs-security-mt.json + config: # override xsappname as it needs to be unique + xsappname: bookshop-mt-${org}-${space} + oauth2-configuration: + credential-types: + - binding-secret + - x509 + redirect-uris: + - https://*.~{app-api/app-domain}/** + requires: + - name: app-api + - name: bookshop-mt-service-manager + type: org.cloudfoundry.managed-service + parameters: + service: service-manager + service-plan: container + - name: bookshop-mt-saas-registry + type: org.cloudfoundry.managed-service + parameters: + service: saas-registry + service-plan: application + config: + appName: bookshop-mt-${org}-${space} # this is the text on the tile + xsappname: bookshop-mt-${org}-${space} # this is the value from xsuaa.parameters.config.xsappname + appUrls: + getDependencies: ~{srv-api/srv-url}/mt/v1.0/subscriptions/dependencies + onSubscription: ~{srv-api/srv-url}/mt/v1.0/subscriptions/tenants/{tenantId} + onSubscriptionAsync: true + onUnSubscriptionAsync: true + onUpdateDependenciesAsync: true + callbackTimeoutMillis: 3600000 + displayName: Multitenancy App ${space} + description: Multitenancy App test deployed using job + category: 'Category' + requires: + - name: srv-api + - name: cf-logging + type: org.cloudfoundry.managed-service + parameters: + service: application-logs + service-plan: lite + - name: sdm + type: org.cloudfoundry.managed-service + parameters: + service: sdm + service-plan: standard diff --git a/app/single-tenant/central-space/demoapp/.gitignore b/app/single-tenant/central-space/demoapp/.gitignore deleted file mode 100644 index c161f228e..000000000 --- a/app/single-tenant/central-space/demoapp/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -**/gen/ -**/edmx/ -*.db -*.sqlite -*.sqlite-wal -*.sqlite-shm -schema*.sql -default-env.json - -**/bin/ -**/target/ -.flattened-pom.xml -.classpath -.project -.settings - -**/node/ -**/node_modules/ - -**/.mta/ -*.mtar - -*.log* -gc_history* -hs_err* -*.tgz -*.iml - -.vscode -.idea -.reloadtrigger diff --git a/app/single-tenant/personal-space/demoapp/.gitignore b/app/single-tenant/personal-space/demoapp/.gitignore deleted file mode 100644 index c161f228e..000000000 --- a/app/single-tenant/personal-space/demoapp/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -**/gen/ -**/edmx/ -*.db -*.sqlite -*.sqlite-wal -*.sqlite-shm -schema*.sql -default-env.json - -**/bin/ -**/target/ -.flattened-pom.xml -.classpath -.project -.settings - -**/node/ -**/node_modules/ - -**/.mta/ -*.mtar - -*.log* -gc_history* -hs_err* -*.tgz -*.iml - -.vscode -.idea -.reloadtrigger From 7faf9660ff6bb6012689d6e966e733465d5d8ca7 Mon Sep 17 00:00:00 2001 From: "Yashmeet ." Date: Thu, 4 Jun 2026 19:46:48 +0530 Subject: [PATCH 3/8] Update action.yml for new app path --- .github/actions/newrelease/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/newrelease/action.yml b/.github/actions/newrelease/action.yml index 04296d557..157842be2 100644 --- a/.github/actions/newrelease/action.yml +++ b/.github/actions/newrelease/action.yml @@ -28,14 +28,14 @@ runs: - name: Update version run: | VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') - echo $VERSION > cap-notebook/version.txt + echo $VERSION > app/single-tenant/central-space/demoapp/version.txt mvn --no-transfer-progress versions:set-property -Dproperty=revision -DnewVersion=$VERSION #chmod +x ensure-license.sh #./ensure-license.sh git config --global user.name 'github-actions[bot]' git config --global user.email 'github-actions[bot]@users.noreply.github.com' git checkout -b develop - git add cap-notebook/version.txt + git add app/single-tenant/central-space/demoapp/version.txt git commit -am "Update version to $VERSION" git push --set-upstream origin develop shell: bash From 7f9a1b436ded7d9ddde2f22377c5222c493036ed Mon Sep 17 00:00:00 2001 From: vibhutikumar <160819926+vibhutikumar07@users.noreply.github.com> Date: Fri, 5 Jun 2026 09:25:11 +0530 Subject: [PATCH 4/8] Workflow Security Hardening (#506) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Harden GitHub Actions workflows — environment, secret masking & log protection Security changes applied to all 19 workflow files: 1. environment: dev — All jobs now pull secrets from the protected "dev" environment instead of repo-level secrets, adding an extra access control layer. Jobs with existing environment (maven-central) are kept as-is. 2. Secrets moved from inline ${{ secrets.X }} to env: blocks — Prevents secret values from appearing in the process argument list (visible via ps/audit logs). Shell commands now reference $ENV_VAR instead. 3. set +x in every sensitive step — Disables bash debug-trace mode before any secret variable is assigned, preventing accidental log exposure if debug mode is ever enabled upstream. 4. ::add-mask:: for all runtime-fetched and copied secret variables — Registers CF credentials, clientSecret/clientID (fetched from XSUAA at runtime), usernames and passwords with GitHub's log scrubber so any accidental echo or error trace is redacted as *** in logs. * Update pom.xml * remove .gitignore from leading apps and add mta.yaml back (#505) Co-authored-by: Yashmeet . * Update multiTenancyDeployLocal.yml * Update pom.xml * modified workflow * Added retry logic * Added Retry logic * modified workflow * updated sdm version * Updated sdm version in pom --------- Co-authored-by: Yashmeet . --- .../workflows/SAPUI5_Version_Monitoring.yml | 1 + .github/workflows/blackduck.yml | 7 +- .github/workflows/cfdeploy.yml | 26 ++++- .github/workflows/codeql.yml | 1 + .github/workflows/demo-build.yml | 1 + .github/workflows/internalArticatory.yml | 8 +- .github/workflows/main-build-and-deploy.yml | 3 + .github/workflows/main-build.yml | 2 + .../workflows/multi tenancy_Integration.yml | 85 ++++++++++---- .github/workflows/multiTenancyDeployLocal.yml | 19 ++- ...ultiTenant_deploy_and_Integration_test.yml | 109 +++++++++++++----- ...loy_and_Integration_test_LatestVersion.yml | 109 +++++++++++++----- .github/workflows/new_wokflow_test.yml | 1 + .github/workflows/pull-request-build.yml | 2 +- ...ngleTenant_deploy_and_Integration_test.yml | 88 +++++++++++--- ...loy_and_Integration_test_LatestVersion.yml | 96 ++++++++++++--- .../singleTenant_integration_test.yml | 71 +++++++++--- .github/workflows/sonarqube.yml | 14 ++- .github/workflows/unit.tests.yml | 1 + 19 files changed, 509 insertions(+), 135 deletions(-) diff --git a/.github/workflows/SAPUI5_Version_Monitoring.yml b/.github/workflows/SAPUI5_Version_Monitoring.yml index c0a688d63..b451c0894 100644 --- a/.github/workflows/SAPUI5_Version_Monitoring.yml +++ b/.github/workflows/SAPUI5_Version_Monitoring.yml @@ -8,6 +8,7 @@ on: jobs: update-version: name: Check and Update SAPUI5 Version + environment: dev runs-on: ubuntu-latest permissions: contents: write diff --git a/.github/workflows/blackduck.yml b/.github/workflows/blackduck.yml index a1763a42e..e4dde42c3 100644 --- a/.github/workflows/blackduck.yml +++ b/.github/workflows/blackduck.yml @@ -16,6 +16,7 @@ permissions: jobs: build: + environment: dev runs-on: ubuntu-latest steps: - name: Checkout code @@ -40,11 +41,15 @@ jobs: run: curl --silent -O https://detect.blackduck.com/detect9.sh - name: Run & analyze BlackDuck Scan + env: + BLACKDUCK_TOKEN: ${{ secrets.BLACKDUCK_TOKEN }} run: | + set +x + echo "::add-mask::$BLACKDUCK_TOKEN" bash ./detect9.sh -d \ --logging.level.com.synopsys.integration=DEBUG \ --blackduck.url="https://sap.blackducksoftware.com" \ - --blackduck.api.token=""${{ secrets.BLACKDUCK_TOKEN }}"" \ + --blackduck.api.token="$BLACKDUCK_TOKEN" \ --detect.blackduck.signature.scanner.arguments="--min-scan-interval=0" \ --detect.maven.build.command="install -P unit-tests -DskipIntegrationTests" \ --detect.latest.release.version="9.6.0" \ diff --git a/.github/workflows/cfdeploy.yml b/.github/workflows/cfdeploy.yml index b8751d4ff..c352b8636 100644 --- a/.github/workflows/cfdeploy.yml +++ b/.github/workflows/cfdeploy.yml @@ -32,6 +32,7 @@ permissions: jobs: Deploy: + environment: dev runs-on: ubuntu-latest if: ${{ github.event.inputs.workflow_choice == 'Deploy' }} @@ -72,6 +73,11 @@ jobs: - name: Prepare and Deploy to Cloud Foundry ☁️ run: | + set +x + echo "::add-mask::$CF_API" + echo "::add-mask::$CF_USER" + echo "::add-mask::$CF_PASSWORD" + echo "::add-mask::$CF_ORG" echo "🔄 Preparing to deploy..." echo "Current Branch: 📂" git branch @@ -108,14 +114,20 @@ jobs: cf install-plugin multiapps -f echo "🔑 Logging into Cloud Foundry..." - cf login -a ${{ secrets.CF_API }} -u ${{ secrets.CF_USER }} -p ${{ secrets.CF_PASSWORD }} -o ${{ secrets.CF_ORG }} -s ${{ github.event.inputs.cf_space }} + cf login -a "$CF_API" -u "$CF_USER" -p "$CF_PASSWORD" -o "$CF_ORG" -s ${{ github.event.inputs.cf_space }} > /dev/null echo "✅ Logged in successfully!" echo "🚀 Running cf deploy..." cf deploy mta_archives/demoappjava_1.0.0.mtar -f echo "✅ Deployment complete!" + env: + CF_API: ${{ secrets.CF_API }} + CF_USER: ${{ secrets.CF_USER }} + CF_PASSWORD: ${{ secrets.CF_PASSWORD }} + CF_ORG: ${{ secrets.CF_ORG }} SnapshotDeploy: + environment: dev runs-on: ubuntu-latest if: ${{ github.event.inputs.workflow_choice == 'Snapshot Deploy' }} @@ -195,6 +207,11 @@ jobs: - name: Prepare and Deploy to Cloud Foundry ☁️ run: | + set +x + echo "::add-mask::$CF_API" + echo "::add-mask::$CF_USER" + echo "::add-mask::$CF_PASSWORD" + echo "::add-mask::$CF_ORG" echo "🔄 Preparing to deploy..." echo "Current Branch: 📂" git branch @@ -231,9 +248,14 @@ jobs: cf install-plugin multiapps -f echo "🔑 Logging into Cloud Foundry..." - cf login -a ${{ secrets.CF_API }} -u ${{ secrets.CF_USER }} -p ${{ secrets.CF_PASSWORD }} -o ${{ secrets.CF_ORG }} -s ${{ github.event.inputs.cf_space }} + cf login -a "$CF_API" -u "$CF_USER" -p "$CF_PASSWORD" -o "$CF_ORG" -s ${{ github.event.inputs.cf_space }} > /dev/null echo "✅ Logged in successfully!" echo "🚀 Running cf deploy..." cf deploy mta_archives/demoappjava_1.0.0.mtar -f echo "✅ Deployment complete!" + env: + CF_API: ${{ secrets.CF_API }} + CF_USER: ${{ secrets.CF_USER }} + CF_PASSWORD: ${{ secrets.CF_PASSWORD }} + CF_ORG: ${{ secrets.CF_ORG }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a5b5476e0..5c6c0df5d 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -13,6 +13,7 @@ on: jobs: analyze: name: Analyze + environment: dev runs-on: ubuntu-latest permissions: diff --git a/.github/workflows/demo-build.yml b/.github/workflows/demo-build.yml index 223c11f04..7936247ec 100644 --- a/.github/workflows/demo-build.yml +++ b/.github/workflows/demo-build.yml @@ -7,6 +7,7 @@ on: jobs: build: + environment: dev runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/internalArticatory.yml b/.github/workflows/internalArticatory.yml index 3dd91871c..d1c7146a4 100644 --- a/.github/workflows/internalArticatory.yml +++ b/.github/workflows/internalArticatory.yml @@ -87,11 +87,17 @@ jobs: - name: Verify artifact in Artifactory if: ${{ endsWith(steps.bump-version.outputs.updated_version || steps.read-revision.outputs.updated_version, '-SNAPSHOT') }} + env: + CAP_DEPLOYMENT_USER: ${{ secrets.CAP_DEPLOYMENT_USER }} + CAP_DEPLOYMENT_PASS: ${{ secrets.CAP_DEPLOYMENT_PASS }} run: | + set +x + echo "::add-mask::$CAP_DEPLOYMENT_USER" + echo "::add-mask::$CAP_DEPLOYMENT_PASS" group_path="com/sap/cds/sdm" version="${{ steps.bump-version.outputs.updated_version || steps.read-revision.outputs.updated_version }}" echo "Checking metadata for $version" - curl -u "${{ secrets.CAP_DEPLOYMENT_USER }}:${{ secrets.CAP_DEPLOYMENT_PASS }}" -f -I \ + curl -u "$CAP_DEPLOYMENT_USER:$CAP_DEPLOYMENT_PASS" -f -I \ "$ARTIFACTORY_URL/$group_path/$version/maven-metadata.xml" || { echo "Metadata not found"; exit 1; } echo "Artifact metadata accessible for $version" - name: Summary diff --git a/.github/workflows/main-build-and-deploy.yml b/.github/workflows/main-build-and-deploy.yml index 0ce1a17b1..4b1fb9bf9 100644 --- a/.github/workflows/main-build-and-deploy.yml +++ b/.github/workflows/main-build-and-deploy.yml @@ -13,6 +13,7 @@ on: jobs: update-version: + environment: dev runs-on: ubuntu-latest #needs: blackduck steps: @@ -36,6 +37,7 @@ jobs: retention-days: 1 build: + environment: dev runs-on: ubuntu-latest needs: update-version steps: @@ -60,6 +62,7 @@ jobs: deploy: name: Deploy to Artifactory + environment: dev runs-on: ubuntu-latest needs: build steps: diff --git a/.github/workflows/main-build.yml b/.github/workflows/main-build.yml index f436f11ed..324e6595e 100644 --- a/.github/workflows/main-build.yml +++ b/.github/workflows/main-build.yml @@ -12,6 +12,7 @@ on: jobs: build: name: Build + environment: dev runs-on: ubuntu-latest permissions: contents: read @@ -30,6 +31,7 @@ jobs: update-version: name: Update version + environment: dev runs-on: ubuntu-latest needs: [ build ] permissions: diff --git a/.github/workflows/multi tenancy_Integration.yml b/.github/workflows/multi tenancy_Integration.yml index 17ec2920f..e71b024ba 100644 --- a/.github/workflows/multi tenancy_Integration.yml +++ b/.github/workflows/multi tenancy_Integration.yml @@ -17,6 +17,7 @@ on: jobs: # Parallel integration tests using matrix strategy integration-test: + environment: dev runs-on: ubuntu-latest strategy: fail-fast: false @@ -65,9 +66,11 @@ jobs: - name: Determine Cloud Foundry Space 🌌 id: determine_space + env: + CF_SPACE: ${{ secrets.CF_SPACE }} run: | if [ "${{ github.event.inputs.cf_space }}" == "developcap" ]; then - space="${{ secrets.CF_SPACE }}" + space="$CF_SPACE" else space="${{ github.event.inputs.cf_space }}" fi @@ -75,13 +78,25 @@ jobs: echo "space=$space" >> $GITHUB_OUTPUT - name: Login to Cloud Foundry 🔑 + env: + CF_API: ${{ secrets.CF_API }} + CF_USER: ${{ secrets.CF_USER }} + CF_PASSWORD: ${{ secrets.CF_PASSWORD }} + CF_ORG: ${{ secrets.CF_ORG }} + CF_SPACE: ${{ secrets.CF_SPACE }} run: | + set +x + echo "::add-mask::$CF_API" + echo "::add-mask::$CF_USER" + echo "::add-mask::$CF_PASSWORD" + echo "::add-mask::$CF_ORG" + echo "::add-mask::$CF_SPACE" echo "🔄 Logging in to Cloud Foundry using space: ${{ steps.determine_space.outputs.space }}" - cf login -a ${{ secrets.CF_API }} \ - -u ${{ secrets.CF_USER }} \ - -p ${{ secrets.CF_PASSWORD }} \ - -o ${{ secrets.CF_ORG }} \ - -s ${{ steps.determine_space.outputs.space }} + cf login -a "$CF_API" \ + -u "$CF_USER" \ + -p "$CF_PASSWORD" \ + -o "$CF_ORG" \ + -s ${{ steps.determine_space.outputs.space }} > /dev/null - name: Fetch and Escape Client Details for single tenant 🔍 id: fetch_credentials @@ -157,23 +172,32 @@ jobs: CLIENT_ID: ${{ steps.fetch_credentials.outputs.CLIENT_ID }} CLIENT_SECRET_MT: ${{ steps.fetch_credentials_mt.outputs.CLIENT_SECRET_MT }} CLIENT_ID_MT: ${{ steps.fetch_credentials_mt.outputs.CLIENT_ID_MT }} + CF_ORG: ${{ secrets.CF_ORG }} + CAPAUTH_URL: ${{ secrets.CAPAUTH_URL }} + AUTHURLMT1: ${{ secrets.AUTHURLMT1 }} + AUTHURLMT2: ${{ secrets.AUTHURLMT2 }} + CF_USER: ${{ secrets.CF_USER }} + CF_PASSWORD: ${{ secrets.CF_PASSWORD }} + NOSDMROLEUSERNAME: ${{ secrets.NOSDMROLEUSERNAME }} + NOSDMROLEUSERPASSWORD: ${{ secrets.NOSDMROLEUSERPASSWORD }} run: | echo "🚀 Preparing credentials for ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}..." + set +x set -e PROPERTIES_FILE="sdm/src/test/resources/credentials.properties" - appUrl="${{ secrets.CF_ORG }}-${{ steps.determine_space.outputs.space }}-demoappjava-srv.cfapps.eu12.hana.ondemand.com" - appUrlMT="${{ secrets.CF_ORG }}-${{ steps.determine_space.outputs.space }}-bookshop-mt-srv.cfapps.eu12.hana.ondemand.com" - authUrl="${{ secrets.CAPAUTH_URL }}" - authUrlMT1="${{ secrets.AUTHURLMT1 }}" - authUrlMT2="${{ secrets.AUTHURLMT2 }}" - clientID="${{ env.CLIENT_ID }}" - clientSecret="${{ env.CLIENT_SECRET }}" - clientIDMT="${{ env.CLIENT_ID_MT }}" - clientSecretMT="${{ env.CLIENT_SECRET_MT }}" - username="${{ secrets.CF_USER }}" - password="${{ secrets.CF_PASSWORD }}" - noSDMRoleUsername="${{ secrets.NOSDMROLEUSERNAME }}" - noSDMRoleUserPassword="${{ secrets.NOSDMROLEUSERPASSWORD }}" + appUrl="$CF_ORG-${{ steps.determine_space.outputs.space }}-demoappjava-srv.cfapps.eu12.hana.ondemand.com" + appUrlMT="$CF_ORG-${{ steps.determine_space.outputs.space }}-bookshop-mt-srv.cfapps.eu12.hana.ondemand.com" + authUrl="$CAPAUTH_URL" + authUrlMT1="$AUTHURLMT1" + authUrlMT2="$AUTHURLMT2" + clientID="$CLIENT_ID" + clientSecret="$CLIENT_SECRET" + clientIDMT="$CLIENT_ID_MT" + clientSecretMT="$CLIENT_SECRET_MT" + username="$CF_USER" + password="$CF_PASSWORD" + noSDMRoleUsername="$NOSDMROLEUSERNAME" + noSDMRoleUserPassword="$NOSDMROLEUSERPASSWORD" echo "::add-mask::$clientSecret" echo "::add-mask::$clientID" @@ -218,8 +242,26 @@ jobs: - name: Run integration tests (${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}) 🎯 run: | echo "🎯 Running Maven integration tests: testClass=${{ matrix.testClass }}, tokenFlow=${{ matrix.tokenFlow }}, tenant=${{ matrix.tenant }}" - mvn clean verify -P integration-tests -DtokenFlow=${{ matrix.tokenFlow }} -DtenancyModel=multi -Dtenant=${{ matrix.tenant }} -DskipUnitTests -Dfailsafe.includes="**/${{ matrix.testClass }}.java" - echo "✅ Integration tests completed for ${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}!" + MAX_RETRIES=3 + ATTEMPT=0 + EXIT_CODE=1 + while [ $ATTEMPT -lt $MAX_RETRIES ]; do + ATTEMPT=$((ATTEMPT + 1)) + echo "🔄 Attempt $ATTEMPT of $MAX_RETRIES..." + if mvn clean verify -P integration-tests -DtokenFlow=${{ matrix.tokenFlow }} -DtenancyModel=multi -Dtenant=${{ matrix.tenant }} -DskipUnitTests -Dfailsafe.includes="**/${{ matrix.testClass }}.java"; then + echo "✅ Tests passed on attempt $ATTEMPT!" + EXIT_CODE=0 + break + else + if [ $ATTEMPT -lt $MAX_RETRIES ]; then + echo "⚠️ Attempt $ATTEMPT failed. Retrying in 30 seconds..." + sleep 30 + else + echo "❌ All $MAX_RETRIES attempts failed for ${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}." + fi + fi + done + exit $EXIT_CODE - name: Upload test results 📊 if: always() @@ -233,6 +275,7 @@ jobs: # Summary job to aggregate results test-summary: + environment: dev runs-on: ubuntu-latest needs: integration-test if: always() diff --git a/.github/workflows/multiTenancyDeployLocal.yml b/.github/workflows/multiTenancyDeployLocal.yml index 79c60c1f8..d2126c701 100644 --- a/.github/workflows/multiTenancyDeployLocal.yml +++ b/.github/workflows/multiTenancyDeployLocal.yml @@ -24,6 +24,7 @@ permissions: jobs: deploy: + environment: dev runs-on: ubuntu-latest steps: @@ -84,7 +85,7 @@ jobs: - name: Set REPOSITORY_ID 🔍 id: set_repository_id run: | - echo "repository_id=${{ secrets.REPOSITORY_ID }}" >> $GITHUB_OUTPUT + echo "repository_id=${{ secrets.MULTITENANT_REPOSITORY_ID }}" >> $GITHUB_OUTPUT - name: Run mbt build 🔨 working-directory: app/multi-tenant/personal-space/cloud-cap-samples-java @@ -98,7 +99,12 @@ jobs: - name: Deploy to Cloud Foundry ☁️ working-directory: app/multi-tenant/personal-space/cloud-cap-samples-java - run: | + env: + CF_API: ${{ secrets.CF_API }} + CF_USER: ${{ secrets.CF_USER }} + CF_PASSWORD: ${{ secrets.CF_PASSWORD }} + CF_ORG: ${{ secrets.CF_ORG }} + run: | echo "🚀 Deploying to -s ${{ steps.determine_space.outputs.space }}..." echo "🔧 Installing Cloud Foundry CLI and plugins..." @@ -107,13 +113,18 @@ jobs: echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list sudo apt update sudo apt install cf8-cli - + cf install-plugin multiapps -f echo "✅ Cloud Foundry CLI setup complete!" # Login to Cloud Foundry again to ensure session is active echo "🔑 Logging in to Cloud Foundry..." - cf login -a ${{ secrets.CF_API }} -u ${{ secrets.CF_USER }} -p ${{ secrets.CF_PASSWORD }} -o ${{ secrets.CF_ORG }} -s ${{ github.event.inputs.cf_space }} + set +x + echo "::add-mask::$CF_API" + echo "::add-mask::$CF_USER" + echo "::add-mask::$CF_PASSWORD" + echo "::add-mask::$CF_ORG" + cf login -a "$CF_API" -u "$CF_USER" -p "$CF_PASSWORD" -o "$CF_ORG" -s ${{ github.event.inputs.cf_space }} > /dev/null echo "✅ Logged in successfully!" # Deploy the application diff --git a/.github/workflows/multiTenant_deploy_and_Integration_test.yml b/.github/workflows/multiTenant_deploy_and_Integration_test.yml index 66bd44aa6..54ed383c6 100644 --- a/.github/workflows/multiTenant_deploy_and_Integration_test.yml +++ b/.github/workflows/multiTenant_deploy_and_Integration_test.yml @@ -15,6 +15,7 @@ permissions: jobs: deploy: + environment: dev if: github.event.pull_request.merged == true runs-on: ubuntu-latest @@ -74,8 +75,20 @@ jobs: - name: Deploy to Cloud Foundry ☁️ working-directory: app/multi-tenant/central-space/cloud-cap-samples-java - run: | - echo "🚀 Deploying to ${{ secrets.CF_SPACE }}..." + env: + CF_API: ${{ secrets.CF_API }} + CF_USER: ${{ secrets.CF_USER }} + CF_PASSWORD: ${{ secrets.CF_PASSWORD }} + CF_ORG: ${{ secrets.CF_ORG }} + CF_SPACE: ${{ secrets.CF_SPACE }} + run: | + set +x + echo "::add-mask::$CF_API" + echo "::add-mask::$CF_USER" + echo "::add-mask::$CF_PASSWORD" + echo "::add-mask::$CF_ORG" + echo "::add-mask::$CF_SPACE" + echo "🚀 Deploying..." echo "🔧 Installing Cloud Foundry CLI and plugins..." # Install cf CLI plugin @@ -83,13 +96,13 @@ jobs: echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list sudo apt update sudo apt install cf8-cli - + cf install-plugin multiapps -f echo "✅ Cloud Foundry CLI setup complete!" # Login to Cloud Foundry again to ensure session is active echo "🔑 Logging in to Cloud Foundry..." - cf login -a ${{ secrets.CF_API }} -u ${{ secrets.CF_USER }} -p ${{ secrets.CF_PASSWORD }} -o ${{ secrets.CF_ORG }} -s ${{ secrets.CF_SPACE }} + cf login -a "$CF_API" -u "$CF_USER" -p "$CF_PASSWORD" -o "$CF_ORG" -s "$CF_SPACE" > /dev/null echo "✅ Logged in successfully!" # Deploy the application @@ -101,6 +114,7 @@ jobs: echo "✅ Deployment complete!" integration-test: + environment: dev needs: deploy runs-on: ubuntu-latest strategy: @@ -148,9 +162,11 @@ jobs: - name: Determine Cloud Foundry Space 🌌 id: determine_space + env: + CF_SPACE: ${{ secrets.CF_SPACE }} run: | if [ "${{ github.event.inputs.cf_space }}" == "developcap" ]; then - space="${{ secrets.CF_SPACE }}" + space="$CF_SPACE" else space="${{ github.event.inputs.cf_space }}" fi @@ -158,13 +174,25 @@ jobs: echo "space=$space" >> $GITHUB_OUTPUT - name: Login to Cloud Foundry 🔑 + env: + CF_API: ${{ secrets.CF_API }} + CF_USER: ${{ secrets.CF_USER }} + CF_PASSWORD: ${{ secrets.CF_PASSWORD }} + CF_ORG: ${{ secrets.CF_ORG }} + CF_SPACE: ${{ secrets.CF_SPACE }} run: | - echo "🔄 Logging in to Cloud Foundry using space: ${{ steps.determine_space.outputs.space }}" - cf login -a ${{ secrets.CF_API }} \ - -u ${{ secrets.CF_USER }} \ - -p ${{ secrets.CF_PASSWORD }} \ - -o ${{ secrets.CF_ORG }} \ - -s ${{ secrets.CF_SPACE }} + set +x + echo "::add-mask::$CF_API" + echo "::add-mask::$CF_USER" + echo "::add-mask::$CF_PASSWORD" + echo "::add-mask::$CF_ORG" + echo "::add-mask::$CF_SPACE" + echo "🔄 Logging in to Cloud Foundry..." + cf login -a "$CF_API" \ + -u "$CF_USER" \ + -p "$CF_PASSWORD" \ + -o "$CF_ORG" \ + -s "$CF_SPACE" > /dev/null - name: Fetch and Escape Client Details for single tenant 🔍 id: fetch_credentials @@ -240,23 +268,33 @@ jobs: CLIENT_ID: ${{ steps.fetch_credentials.outputs.CLIENT_ID }} CLIENT_SECRET_MT: ${{ steps.fetch_credentials_mt.outputs.CLIENT_SECRET_MT }} CLIENT_ID_MT: ${{ steps.fetch_credentials_mt.outputs.CLIENT_ID_MT }} + CF_ORG: ${{ secrets.CF_ORG }} + CF_SPACE: ${{ secrets.CF_SPACE }} + CAPAUTH_URL: ${{ secrets.CAPAUTH_URL }} + AUTHURLMT1: ${{ secrets.AUTHURLMT1 }} + AUTHURLMT2: ${{ secrets.AUTHURLMT2 }} + CF_USER: ${{ secrets.CF_USER }} + CF_PASSWORD: ${{ secrets.CF_PASSWORD }} + NOSDMROLEUSERNAME: ${{ secrets.NOSDMROLEUSERNAME }} + NOSDMROLEUSERPASSWORD: ${{ secrets.NOSDMROLEUSERPASSWORD }} run: | echo "🚀 Preparing credentials for ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}..." + set +x set -e PROPERTIES_FILE="sdm/src/test/resources/credentials.properties" - appUrl="${{ secrets.CF_ORG }}-${{ secrets.CF_SPACE }}-demoappjava-srv.cfapps.eu12.hana.ondemand.com" - appUrlMT="${{ secrets.CF_ORG }}-${{ secrets.CF_SPACE }}-bookshop-mt-srv.cfapps.eu12.hana.ondemand.com" - authUrl="${{ secrets.CAPAUTH_URL }}" - authUrlMT1="${{ secrets.AUTHURLMT1 }}" - authUrlMT2="${{ secrets.AUTHURLMT2 }}" - clientID="${{ env.CLIENT_ID }}" - clientSecret="${{ env.CLIENT_SECRET }}" - clientIDMT="${{ env.CLIENT_ID_MT }}" - clientSecretMT="${{ env.CLIENT_SECRET_MT }}" - username="${{ secrets.CF_USER }}" - password="${{ secrets.CF_PASSWORD }}" - noSDMRoleUsername="${{ secrets.NOSDMROLEUSERNAME }}" - noSDMRoleUserPassword="${{ secrets.NOSDMROLEUSERPASSWORD }}" + appUrl="$CF_ORG-$CF_SPACE-demoappjava-srv.cfapps.eu12.hana.ondemand.com" + appUrlMT="$CF_ORG-$CF_SPACE-bookshop-mt-srv.cfapps.eu12.hana.ondemand.com" + authUrl="$CAPAUTH_URL" + authUrlMT1="$AUTHURLMT1" + authUrlMT2="$AUTHURLMT2" + clientID="$CLIENT_ID" + clientSecret="$CLIENT_SECRET" + clientIDMT="$CLIENT_ID_MT" + clientSecretMT="$CLIENT_SECRET_MT" + username="$CF_USER" + password="$CF_PASSWORD" + noSDMRoleUsername="$NOSDMROLEUSERNAME" + noSDMRoleUserPassword="$NOSDMROLEUSERPASSWORD" echo "::add-mask::$clientSecret" echo "::add-mask::$clientID" @@ -301,8 +339,26 @@ jobs: - name: Run integration tests (${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}) 🎯 run: | echo "🎯 Running Maven integration tests: testClass=${{ matrix.testClass }}, tokenFlow=${{ matrix.tokenFlow }}, tenant=${{ matrix.tenant }}" - mvn clean verify -P integration-tests -DtokenFlow=${{ matrix.tokenFlow }} -DtenancyModel=multi -Dtenant=${{ matrix.tenant }} -DskipUnitTests -Dfailsafe.includes="**/${{ matrix.testClass }}.java" - echo "✅ Integration tests completed for ${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}!" + MAX_RETRIES=3 + ATTEMPT=0 + EXIT_CODE=1 + while [ $ATTEMPT -lt $MAX_RETRIES ]; do + ATTEMPT=$((ATTEMPT + 1)) + echo "🔄 Attempt $ATTEMPT of $MAX_RETRIES..." + if mvn clean verify -P integration-tests -DtokenFlow=${{ matrix.tokenFlow }} -DtenancyModel=multi -Dtenant=${{ matrix.tenant }} -DskipUnitTests -Dfailsafe.includes="**/${{ matrix.testClass }}.java"; then + echo "✅ Tests passed on attempt $ATTEMPT!" + EXIT_CODE=0 + break + else + if [ $ATTEMPT -lt $MAX_RETRIES ]; then + echo "⚠️ Attempt $ATTEMPT failed. Retrying in 30 seconds..." + sleep 30 + else + echo "❌ All $MAX_RETRIES attempts failed for ${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}." + fi + fi + done + exit $EXIT_CODE - name: Upload test results 📊 if: always() @@ -316,6 +372,7 @@ jobs: # Summary job to aggregate results test-summary: + environment: dev runs-on: ubuntu-latest needs: integration-test if: always() && github.event.pull_request.merged == true diff --git a/.github/workflows/multiTenant_deploy_and_Integration_test_LatestVersion.yml b/.github/workflows/multiTenant_deploy_and_Integration_test_LatestVersion.yml index 8681a2fd4..8ceb9cb5f 100644 --- a/.github/workflows/multiTenant_deploy_and_Integration_test_LatestVersion.yml +++ b/.github/workflows/multiTenant_deploy_and_Integration_test_LatestVersion.yml @@ -15,6 +15,7 @@ permissions: jobs: deploy: + environment: dev #Run only if the triggering workflow concluded successfully if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }} runs-on: ubuntu-latest @@ -121,8 +122,20 @@ jobs: - name: Deploy to Cloud Foundry ☁️ working-directory: app/multi-tenant/central-space/cloud-cap-samples-java - run: | - echo "🚀 Deploying to ${{ secrets.CF_SPACE }}..." + env: + CF_API: ${{ secrets.CF_API }} + CF_USER: ${{ secrets.CF_USER }} + CF_PASSWORD: ${{ secrets.CF_PASSWORD }} + CF_ORG: ${{ secrets.CF_ORG }} + CF_SPACE: ${{ secrets.CF_SPACE }} + run: | + set +x + echo "::add-mask::$CF_API" + echo "::add-mask::$CF_USER" + echo "::add-mask::$CF_PASSWORD" + echo "::add-mask::$CF_ORG" + echo "::add-mask::$CF_SPACE" + echo "🚀 Deploying..." echo "🔧 Installing Cloud Foundry CLI and plugins..." # Install cf CLI plugin @@ -130,13 +143,13 @@ jobs: echo "deb https://packages.cloudfoundry.org/debian stable main" | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list sudo apt update sudo apt install cf8-cli - + cf install-plugin multiapps -f echo "✅ Cloud Foundry CLI setup complete!" # Login to Cloud Foundry again to ensure session is active echo "🔑 Logging in to Cloud Foundry..." - cf login -a ${{ secrets.CF_API }} -u ${{ secrets.CF_USER }} -p ${{ secrets.CF_PASSWORD }} -o ${{ secrets.CF_ORG }} -s ${{ secrets.CF_SPACE }} + cf login -a "$CF_API" -u "$CF_USER" -p "$CF_PASSWORD" -o "$CF_ORG" -s "$CF_SPACE" > /dev/null echo "✅ Logged in successfully!" # Deploy the application @@ -148,6 +161,7 @@ jobs: echo "✅ Deployment complete!" integration-test: + environment: dev needs: deploy runs-on: ubuntu-latest strategy: @@ -195,9 +209,11 @@ jobs: - name: Determine Cloud Foundry Space 🌌 id: determine_space + env: + CF_SPACE: ${{ secrets.CF_SPACE }} run: | if [ "${{ github.event.inputs.cf_space }}" == "developcap" ]; then - space="${{ secrets.CF_SPACE }}" + space="$CF_SPACE" else space="${{ github.event.inputs.cf_space }}" fi @@ -205,13 +221,25 @@ jobs: echo "space=$space" >> $GITHUB_OUTPUT - name: Login to Cloud Foundry 🔑 + env: + CF_API: ${{ secrets.CF_API }} + CF_USER: ${{ secrets.CF_USER }} + CF_PASSWORD: ${{ secrets.CF_PASSWORD }} + CF_ORG: ${{ secrets.CF_ORG }} + CF_SPACE: ${{ secrets.CF_SPACE }} run: | - echo "🔄 Logging in to Cloud Foundry using space: ${{ steps.determine_space.outputs.space }}" - cf login -a ${{ secrets.CF_API }} \ - -u ${{ secrets.CF_USER }} \ - -p ${{ secrets.CF_PASSWORD }} \ - -o ${{ secrets.CF_ORG }} \ - -s ${{ secrets.CF_SPACE }} + set +x + echo "::add-mask::$CF_API" + echo "::add-mask::$CF_USER" + echo "::add-mask::$CF_PASSWORD" + echo "::add-mask::$CF_ORG" + echo "::add-mask::$CF_SPACE" + echo "🔄 Logging in to Cloud Foundry..." + cf login -a "$CF_API" \ + -u "$CF_USER" \ + -p "$CF_PASSWORD" \ + -o "$CF_ORG" \ + -s "$CF_SPACE" > /dev/null - name: Fetch and Escape Client Details for single tenant 🔍 id: fetch_credentials @@ -287,23 +315,33 @@ jobs: CLIENT_ID: ${{ steps.fetch_credentials.outputs.CLIENT_ID }} CLIENT_SECRET_MT: ${{ steps.fetch_credentials_mt.outputs.CLIENT_SECRET_MT }} CLIENT_ID_MT: ${{ steps.fetch_credentials_mt.outputs.CLIENT_ID_MT }} + CF_ORG: ${{ secrets.CF_ORG }} + CF_SPACE: ${{ secrets.CF_SPACE }} + CAPAUTH_URL: ${{ secrets.CAPAUTH_URL }} + AUTHURLMT1: ${{ secrets.AUTHURLMT1 }} + AUTHURLMT2: ${{ secrets.AUTHURLMT2 }} + CF_USER: ${{ secrets.CF_USER }} + CF_PASSWORD: ${{ secrets.CF_PASSWORD }} + NOSDMROLEUSERNAME: ${{ secrets.NOSDMROLEUSERNAME }} + NOSDMROLEUSERPASSWORD: ${{ secrets.NOSDMROLEUSERPASSWORD }} run: | echo "🚀 Preparing credentials for ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}..." + set +x set -e PROPERTIES_FILE="sdm/src/test/resources/credentials.properties" - appUrl="${{ secrets.CF_ORG }}-${{ secrets.CF_SPACE }}-demoappjava-srv.cfapps.eu12.hana.ondemand.com" - appUrlMT="${{ secrets.CF_ORG }}-${{ secrets.CF_SPACE }}-bookshop-mt-srv.cfapps.eu12.hana.ondemand.com" - authUrl="${{ secrets.CAPAUTH_URL }}" - authUrlMT1="${{ secrets.AUTHURLMT1 }}" - authUrlMT2="${{ secrets.AUTHURLMT2 }}" - clientID="${{ env.CLIENT_ID }}" - clientSecret="${{ env.CLIENT_SECRET }}" - clientIDMT="${{ env.CLIENT_ID_MT }}" - clientSecretMT="${{ env.CLIENT_SECRET_MT }}" - username="${{ secrets.CF_USER }}" - password="${{ secrets.CF_PASSWORD }}" - noSDMRoleUsername="${{ secrets.NOSDMROLEUSERNAME }}" - noSDMRoleUserPassword="${{ secrets.NOSDMROLEUSERPASSWORD }}" + appUrl="$CF_ORG-$CF_SPACE-demoappjava-srv.cfapps.eu12.hana.ondemand.com" + appUrlMT="$CF_ORG-$CF_SPACE-bookshop-mt-srv.cfapps.eu12.hana.ondemand.com" + authUrl="$CAPAUTH_URL" + authUrlMT1="$AUTHURLMT1" + authUrlMT2="$AUTHURLMT2" + clientID="$CLIENT_ID" + clientSecret="$CLIENT_SECRET" + clientIDMT="$CLIENT_ID_MT" + clientSecretMT="$CLIENT_SECRET_MT" + username="$CF_USER" + password="$CF_PASSWORD" + noSDMRoleUsername="$NOSDMROLEUSERNAME" + noSDMRoleUserPassword="$NOSDMROLEUSERPASSWORD" echo "::add-mask::$clientSecret" echo "::add-mask::$clientID" @@ -348,8 +386,26 @@ jobs: - name: Run integration tests (${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}) 🎯 run: | echo "🎯 Running Maven integration tests: testClass=${{ matrix.testClass }}, tokenFlow=${{ matrix.tokenFlow }}, tenant=${{ matrix.tenant }}" - mvn clean verify -P integration-tests -DtokenFlow=${{ matrix.tokenFlow }} -DtenancyModel=multi -Dtenant=${{ matrix.tenant }} -DskipUnitTests -Dfailsafe.includes="**/${{ matrix.testClass }}.java" - echo "✅ Integration tests completed for ${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}!" + MAX_RETRIES=3 + ATTEMPT=0 + EXIT_CODE=1 + while [ $ATTEMPT -lt $MAX_RETRIES ]; do + ATTEMPT=$((ATTEMPT + 1)) + echo "🔄 Attempt $ATTEMPT of $MAX_RETRIES..." + if mvn clean verify -P integration-tests -DtokenFlow=${{ matrix.tokenFlow }} -DtenancyModel=multi -Dtenant=${{ matrix.tenant }} -DskipUnitTests -Dfailsafe.includes="**/${{ matrix.testClass }}.java"; then + echo "✅ Tests passed on attempt $ATTEMPT!" + EXIT_CODE=0 + break + else + if [ $ATTEMPT -lt $MAX_RETRIES ]; then + echo "⚠️ Attempt $ATTEMPT failed. Retrying in 30 seconds..." + sleep 30 + else + echo "❌ All $MAX_RETRIES attempts failed for ${{ matrix.testClass }} - ${{ matrix.tokenFlow }} - ${{ matrix.tenant }}." + fi + fi + done + exit $EXIT_CODE - name: Upload test results 📊 if: always() @@ -363,6 +419,7 @@ jobs: # Summary job to aggregate results test-summary: + environment: dev runs-on: ubuntu-latest needs: integration-test if: always() diff --git a/.github/workflows/new_wokflow_test.yml b/.github/workflows/new_wokflow_test.yml index 6d957adc1..37c742171 100644 --- a/.github/workflows/new_wokflow_test.yml +++ b/.github/workflows/new_wokflow_test.yml @@ -7,6 +7,7 @@ on: workflow_dispatch: jobs: check_release_branches: + environment: dev if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }} runs-on: ubuntu-latest diff --git a/.github/workflows/pull-request-build.yml b/.github/workflows/pull-request-build.yml index 7ebbf875b..9fa18c50a 100644 --- a/.github/workflows/pull-request-build.yml +++ b/.github/workflows/pull-request-build.yml @@ -11,7 +11,7 @@ on: jobs: build: - + environment: dev runs-on: ubuntu-latest strategy: diff --git a/.github/workflows/singleTenant_deploy_and_Integration_test.yml b/.github/workflows/singleTenant_deploy_and_Integration_test.yml index a7b495160..f62e5f3ee 100644 --- a/.github/workflows/singleTenant_deploy_and_Integration_test.yml +++ b/.github/workflows/singleTenant_deploy_and_Integration_test.yml @@ -14,6 +14,7 @@ permissions: jobs: deploy: + environment: dev if: github.event.pull_request.merged == true runs-on: ubuntu-latest @@ -67,6 +68,12 @@ jobs: - name: Prepare and Deploy to Cloud Foundry run: | + set +x + echo "::add-mask::$CF_API" + echo "::add-mask::$CF_USER" + echo "::add-mask::$CF_PASSWORD" + echo "::add-mask::$CF_ORG" + echo "::add-mask::$CF_SPACE" echo "Current Branch......" git branch pwd @@ -88,25 +95,32 @@ jobs: mbt build - # Install cf & login + # Install cf & login wget -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key \ | sudo tee /etc/apt/trusted.gpg.d/cloudfoundry.asc echo "deb https://packages.cloudfoundry.org/debian stable main" \ | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list sudo apt update sudo apt install cf8-cli - + # Install cf CLI plugin cf install-plugin multiapps -f # Login to Cloud Foundry again to ensure session is active - cf login -a ${{ secrets.CF_API }} -u ${{ secrets.CF_USER }} -p ${{ secrets.CF_PASSWORD }} -o ${{ secrets.CF_ORG }} -s ${{ secrets.CF_SPACE }} + cf login -a "$CF_API" -u "$CF_USER" -p "$CF_PASSWORD" -o "$CF_ORG" -s "$CF_SPACE" > /dev/null # Deploy the application echo "Running cf deploy" cf deploy mta_archives/demoappjava_1.0.0.mtar -f + env: + CF_API: ${{ secrets.CF_API }} + CF_USER: ${{ secrets.CF_USER }} + CF_PASSWORD: ${{ secrets.CF_PASSWORD }} + CF_ORG: ${{ secrets.CF_ORG }} + CF_SPACE: ${{ secrets.CF_SPACE }} integration-test: + environment: dev needs: deploy runs-on: ubuntu-latest strategy: @@ -151,12 +165,24 @@ jobs: fi - name: Login to Cloud Foundry + env: + CF_API: ${{ secrets.CF_API }} + CF_USER: ${{ secrets.CF_USER }} + CF_PASSWORD: ${{ secrets.CF_PASSWORD }} + CF_ORG: ${{ secrets.CF_ORG }} + CF_SPACE: ${{ secrets.CF_SPACE }} run: | - cf login -a ${{ secrets.CF_API }} \ - -u ${{ secrets.CF_USER }} \ - -p ${{ secrets.CF_PASSWORD }} \ - -o ${{ secrets.CF_ORG }} \ - -s ${{ secrets.CF_SPACE }} + set +x + echo "::add-mask::$CF_API" + echo "::add-mask::$CF_USER" + echo "::add-mask::$CF_PASSWORD" + echo "::add-mask::$CF_ORG" + echo "::add-mask::$CF_SPACE" + cf login -a "$CF_API" \ + -u "$CF_USER" \ + -p "$CF_PASSWORD" \ + -o "$CF_ORG" \ + -s "$CF_SPACE" > /dev/null - name: Fetch and Escape Client Details for single tenant 🔍 id: fetch_credentials @@ -190,18 +216,26 @@ jobs: env: CLIENT_SECRET: ${{ steps.fetch_credentials.outputs.CLIENT_SECRET }} CLIENT_ID: ${{ steps.fetch_credentials.outputs.CLIENT_ID }} + CF_ORG: ${{ secrets.CF_ORG }} + CF_SPACE: ${{ secrets.CF_SPACE }} + CAPAUTH_URL: ${{ secrets.CAPAUTH_URL }} + CF_USER: ${{ secrets.CF_USER }} + CF_PASSWORD: ${{ secrets.CF_PASSWORD }} + NOSDMROLEUSERNAME: ${{ secrets.NOSDMROLEUSERNAME }} + NOSDMROLEUSERPASSWORD: ${{ secrets.NOSDMROLEUSERPASSWORD }} run: | + set +x echo "🚀 Starting integration tests for ${{ matrix.tokenFlow }} - ${{ matrix.testClass }}..." set -e PROPERTIES_FILE="sdm/src/test/resources/credentials.properties" - appUrl="${{ secrets.CF_ORG }}-${{ secrets.CF_SPACE }}-demoappjava-srv.cfapps.eu12.hana.ondemand.com" - authUrl="${{ secrets.CAPAUTH_URL }}" - clientID="${{ env.CLIENT_ID }}" - clientSecret="${{ env.CLIENT_SECRET }}" - username="${{ secrets.CF_USER }}" - password="${{ secrets.CF_PASSWORD }}" - noSDMRoleUsername="${{ secrets.NOSDMROLEUSERNAME }}" - noSDMRoleUserPassword="${{ secrets.NOSDMROLEUSERPASSWORD }}" + appUrl="$CF_ORG-$CF_SPACE-demoappjava-srv.cfapps.eu12.hana.ondemand.com" + authUrl="$CAPAUTH_URL" + clientID="$CLIENT_ID" + clientSecret="$CLIENT_SECRET" + username="$CF_USER" + password="$CF_PASSWORD" + noSDMRoleUsername="$NOSDMROLEUSERNAME" + noSDMRoleUserPassword="$NOSDMROLEUSERPASSWORD" echo "::add-mask::$clientSecret" echo "::add-mask::$clientID" echo "::add-mask::$username" @@ -227,7 +261,27 @@ jobs: noSDMRoleUserPassword=$noSDMRoleUserPassword EOL echo "🎯 Running Maven integration tests for ${{ matrix.tokenFlow }} - ${{ matrix.testClass }}..." - mvn clean verify -P integration-tests -DtokenFlow=${{ matrix.tokenFlow }} -DtenancyModel=single -DskipUnitTests -Dfailsafe.includes="**/${{ matrix.testClass }}.java" + # mvn clean verify -P integration-tests -DtokenFlow=${{ matrix.tokenFlow }} -DtenancyModel=single -DskipUnitTests -Dfailsafe.includes="**/${{ matrix.testClass }}.java" + MAX_RETRIES=3 + ATTEMPT=0 + EXIT_CODE=1 + while [ $ATTEMPT -lt $MAX_RETRIES ]; do + ATTEMPT=$((ATTEMPT + 1)) + echo "🔄 Attempt $ATTEMPT of $MAX_RETRIES..." + if mvn clean verify -P integration-tests -DtokenFlow=${{ matrix.tokenFlow }} -DtenancyModel=single -DskipUnitTests -Dfailsafe.includes="**/${{ matrix.testClass }}.java"; then + echo "✅ Tests passed on attempt $ATTEMPT!" + EXIT_CODE=0 + break + else + if [ $ATTEMPT -lt $MAX_RETRIES ]; then + echo "⚠️ Attempt $ATTEMPT failed. Retrying in 30 seconds..." + sleep 30 + else + echo "❌ All $MAX_RETRIES attempts failed for ${{ matrix.tokenFlow }} - ${{ matrix.testClass }}." + fi + fi + done + exit $EXIT_CODE diff --git a/.github/workflows/singleTenant_deploy_and_Integration_test_LatestVersion.yml b/.github/workflows/singleTenant_deploy_and_Integration_test_LatestVersion.yml index 50bae680d..a4991ba6c 100644 --- a/.github/workflows/singleTenant_deploy_and_Integration_test_LatestVersion.yml +++ b/.github/workflows/singleTenant_deploy_and_Integration_test_LatestVersion.yml @@ -16,6 +16,7 @@ permissions: jobs: deploy: + environment: dev # Run only if the triggering workflow concluded successfully if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }} runs-on: ubuntu-latest @@ -118,6 +119,12 @@ jobs: - name: Prepare and Deploy to Cloud Foundry run: | + set +x + echo "::add-mask::$CF_API" + echo "::add-mask::$CF_USER" + echo "::add-mask::$CF_PASSWORD" + echo "::add-mask::$CF_ORG" + echo "::add-mask::$CF_SPACE" echo "Current Branch......" git branch pwd @@ -139,25 +146,32 @@ jobs: mbt build - # Install cf & login + # Install cf & login wget -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key \ | sudo tee /etc/apt/trusted.gpg.d/cloudfoundry.asc echo "deb https://packages.cloudfoundry.org/debian stable main" \ | sudo tee /etc/apt/sources.list.d/cloudfoundry-cli.list sudo apt update sudo apt install cf8-cli - + # Install cf CLI plugin cf install-plugin multiapps -f # Login to Cloud Foundry again to ensure session is active - cf login -a ${{ secrets.CF_API }} -u ${{ secrets.CF_USER }} -p ${{ secrets.CF_PASSWORD }} -o ${{ secrets.CF_ORG }} -s ${{ secrets.CF_SPACE }} + cf login -a "$CF_API" -u "$CF_USER" -p "$CF_PASSWORD" -o "$CF_ORG" -s "$CF_SPACE" > /dev/null # Deploy the application echo "Running cf deploy" cf deploy mta_archives/demoappjava_1.0.0.mtar -f + env: + CF_API: ${{ secrets.CF_API }} + CF_USER: ${{ secrets.CF_USER }} + CF_PASSWORD: ${{ secrets.CF_PASSWORD }} + CF_ORG: ${{ secrets.CF_ORG }} + CF_SPACE: ${{ secrets.CF_SPACE }} integration-test: + environment: dev needs: deploy runs-on: ubuntu-latest strategy: @@ -202,12 +216,24 @@ jobs: fi - name: Login to Cloud Foundry + env: + CF_API: ${{ secrets.CF_API }} + CF_USER: ${{ secrets.CF_USER }} + CF_PASSWORD: ${{ secrets.CF_PASSWORD }} + CF_ORG: ${{ secrets.CF_ORG }} + CF_SPACE: ${{ secrets.CF_SPACE }} run: | - cf login -a ${{ secrets.CF_API }} \ - -u ${{ secrets.CF_USER }} \ - -p ${{ secrets.CF_PASSWORD }} \ - -o ${{ secrets.CF_ORG }} \ - -s ${{ secrets.CF_SPACE }} + set +x + echo "::add-mask::$CF_API" + echo "::add-mask::$CF_USER" + echo "::add-mask::$CF_PASSWORD" + echo "::add-mask::$CF_ORG" + echo "::add-mask::$CF_SPACE" + cf login -a "$CF_API" \ + -u "$CF_USER" \ + -p "$CF_PASSWORD" \ + -o "$CF_ORG" \ + -s "$CF_SPACE" > /dev/null - name: Fetch and Escape Client Secret id: fetch_secret @@ -234,23 +260,39 @@ jobs: # Escape any $ characters in the clientSecret escapedClientSecret=$(echo "$clientSecret" | sed 's/\$/\\$/g') + echo "::add-mask::$escapedClientSecret" echo "CLIENT_SECRET=$escapedClientSecret" >> $GITHUB_OUTPUT - name: Run integration tests (${{ matrix.tokenFlow }} - ${{ matrix.testClass }}) env: CLIENT_SECRET: ${{ steps.fetch_secret.outputs.CLIENT_SECRET }} + CF_ORG: ${{ secrets.CF_ORG }} + CF_SPACE: ${{ secrets.CF_SPACE }} + CAPAUTH_URL: ${{ secrets.CAPAUTH_URL }} + CAPSDM_CLIENT_ID: ${{ secrets.CAPSDM_CLIENT_ID }} + CF_USER: ${{ secrets.CF_USER }} + CF_PASSWORD: ${{ secrets.CF_PASSWORD }} + NOSDMROLEUSERNAME: ${{ secrets.NOSDMROLEUSERNAME }} + NOSDMROLEUSERPASSWORD: ${{ secrets.NOSDMROLEUSERPASSWORD }} run: | + set +x echo "Starting integration tests for ${{ matrix.tokenFlow }} - ${{ matrix.testClass }}..." set -e # Enable error checking PROPERTIES_FILE="sdm/src/test/resources/credentials.properties" # Gather secrets and other values - appUrl="${{ secrets.CF_ORG }}-${{ secrets.CF_SPACE }}-demoappjava-srv.cfapps.eu12.hana.ondemand.com" - authUrl="${{ secrets.CAPAUTH_URL }}" - clientID="${{ secrets.CAPSDM_CLIENT_ID }}" - clientSecret="${{ env.CLIENT_SECRET }}" - username="${{ secrets.CF_USER }}" - password="${{ secrets.CF_PASSWORD }}" - noSDMRoleUsername="${{ secrets.NOSDMROLEUSERNAME }}" - noSDMRoleUserPassword="${{ secrets.NOSDMROLEUSERPASSWORD }}" + appUrl="$CF_ORG-$CF_SPACE-demoappjava-srv.cfapps.eu12.hana.ondemand.com" + authUrl="$CAPAUTH_URL" + clientID="$CAPSDM_CLIENT_ID" + clientSecret="$CLIENT_SECRET" + username="$CF_USER" + password="$CF_PASSWORD" + noSDMRoleUsername="$NOSDMROLEUSERNAME" + noSDMRoleUserPassword="$NOSDMROLEUSERPASSWORD" + echo "::add-mask::$clientID" + echo "::add-mask::$clientSecret" + echo "::add-mask::$username" + echo "::add-mask::$password" + echo "::add-mask::$noSDMRoleUsername" + echo "::add-mask::$noSDMRoleUserPassword" # Ensure all required variables are set if [ -z "$appUrl" ]; then echo "Error: appUrl is not set"; exit 1; fi if [ -z "$authUrl" ]; then echo "Error: authUrl is not set"; exit 1; fi @@ -273,6 +315,26 @@ jobs: EOL # Run Maven integration tests echo "Running Maven integration tests for ${{ matrix.tokenFlow }} - ${{ matrix.testClass }}..." - mvn clean verify -P integration-tests -DtokenFlow=${{ matrix.tokenFlow }} -DtenancyModel=single -DskipUnitTests -Dfailsafe.includes="**/${{ matrix.testClass }}.java" + # mvn clean verify -P integration-tests -DtokenFlow=${{ matrix.tokenFlow }} -DtenancyModel=single -DskipUnitTests -Dfailsafe.includes="**/${{ matrix.testClass }}.java" + MAX_RETRIES=3 + ATTEMPT=0 + EXIT_CODE=1 + while [ $ATTEMPT -lt $MAX_RETRIES ]; do + ATTEMPT=$((ATTEMPT + 1)) + echo "🔄 Attempt $ATTEMPT of $MAX_RETRIES..." + if mvn clean verify -P integration-tests -DtokenFlow=${{ matrix.tokenFlow }} -DtenancyModel=single -DskipUnitTests -Dfailsafe.includes="**/${{ matrix.testClass }}.java"; then + echo "✅ Tests passed on attempt $ATTEMPT!" + EXIT_CODE=0 + break + else + if [ $ATTEMPT -lt $MAX_RETRIES ]; then + echo "⚠️ Attempt $ATTEMPT failed. Retrying in 30 seconds..." + sleep 30 + else + echo "❌ All $MAX_RETRIES attempts failed for ${{ matrix.tokenFlow }} - ${{ matrix.testClass }}." + fi + fi + done + exit $EXIT_CODE diff --git a/.github/workflows/singleTenant_integration_test.yml b/.github/workflows/singleTenant_integration_test.yml index dc4ab243b..538599761 100644 --- a/.github/workflows/singleTenant_integration_test.yml +++ b/.github/workflows/singleTenant_integration_test.yml @@ -13,6 +13,7 @@ on: jobs: integration-test: + environment: dev runs-on: ubuntu-latest strategy: fail-fast: false @@ -60,9 +61,11 @@ jobs: - name: Determine Cloud Foundry Space 🌌 id: determine_space + env: + CF_SPACE: ${{ secrets.CF_SPACE }} run: | if [ "${{ github.event.inputs.cf_space }}" == "developcap" ]; then - space="${{ secrets.CF_SPACE }}" + space="$CF_SPACE" else space="${{ github.event.inputs.cf_space }}" fi @@ -70,14 +73,25 @@ jobs: echo "space=$space" >> $GITHUB_OUTPUT - name: Login to Cloud Foundry 🔑 + env: + CF_API: ${{ secrets.CF_API }} + CF_USER: ${{ secrets.CF_USER }} + CF_PASSWORD: ${{ secrets.CF_PASSWORD }} + CF_ORG: ${{ secrets.CF_ORG }} run: | + set +x + echo "::add-mask::$CF_API" + echo "::add-mask::$CF_USER" + echo "::add-mask::$CF_PASSWORD" + echo "::add-mask::$CF_ORG" + echo "::add-mask::${{ steps.determine_space.outputs.space }}" echo "🔄 Logging in to Cloud Foundry..." echo "Space Name: ${{ steps.determine_space.outputs.space }}" - cf login -a ${{ secrets.CF_API }} \ - -u ${{ secrets.CF_USER }} \ - -p ${{ secrets.CF_PASSWORD }} \ - -o ${{ secrets.CF_ORG }} \ - -s ${{ steps.determine_space.outputs.space }} + cf login -a "$CF_API" \ + -u "$CF_USER" \ + -p "$CF_PASSWORD" \ + -o "$CF_ORG" \ + -s ${{ steps.determine_space.outputs.space }} > /dev/null echo "✅ Logged in successfully!" - name: Fetch and Escape Client Details for single tenant 🔍 @@ -113,18 +127,25 @@ jobs: env: CLIENT_SECRET: ${{ steps.fetch_credentials.outputs.CLIENT_SECRET }} CLIENT_ID: ${{ steps.fetch_credentials.outputs.CLIENT_ID }} + CF_ORG: ${{ secrets.CF_ORG }} + CAPAUTH_URL: ${{ secrets.CAPAUTH_URL }} + CF_USER: ${{ secrets.CF_USER }} + CF_PASSWORD: ${{ secrets.CF_PASSWORD }} + NOSDMROLEUSERNAME: ${{ secrets.NOSDMROLEUSERNAME }} + NOSDMROLEUSERPASSWORD: ${{ secrets.NOSDMROLEUSERPASSWORD }} run: | + set +x echo "🚀 Starting integration tests for ${{ matrix.tokenFlow }} - ${{ matrix.testClass }}..." set -e PROPERTIES_FILE="sdm/src/test/resources/credentials.properties" - appUrl="${{ secrets.CF_ORG }}-${{ steps.determine_space.outputs.space }}-demoappjava-srv.cfapps.eu12.hana.ondemand.com" - authUrl="${{ secrets.CAPAUTH_URL }}" - clientID="${{ env.CLIENT_ID }}" - clientSecret="${{ env.CLIENT_SECRET }}" - username="${{ secrets.CF_USER }}" - password="${{ secrets.CF_PASSWORD }}" - noSDMRoleUsername="${{ secrets.NOSDMROLEUSERNAME }}" - noSDMRoleUserPassword="${{ secrets.NOSDMROLEUSERPASSWORD }}" + appUrl="$CF_ORG-${{ steps.determine_space.outputs.space }}-demoappjava-srv.cfapps.eu12.hana.ondemand.com" + authUrl="$CAPAUTH_URL" + clientID="$CLIENT_ID" + clientSecret="$CLIENT_SECRET" + username="$CF_USER" + password="$CF_PASSWORD" + noSDMRoleUsername="$NOSDMROLEUSERNAME" + noSDMRoleUserPassword="$NOSDMROLEUSERPASSWORD" echo "::add-mask::$clientSecret" echo "::add-mask::$clientID" echo "::add-mask::$username" @@ -150,4 +171,24 @@ jobs: noSDMRoleUserPassword=$noSDMRoleUserPassword EOL echo "🎯 Running Maven integration tests for ${{ matrix.tokenFlow }} - ${{ matrix.testClass }}..." - mvn clean verify -P integration-tests -DtokenFlow=${{ matrix.tokenFlow }} -DtenancyModel=single -DskipUnitTests -Dfailsafe.includes="**/${{ matrix.testClass }}.java" + # mvn clean verify -P integration-tests -DtokenFlow=${{ matrix.tokenFlow }} -DtenancyModel=single -DskipUnitTests -Dfailsafe.includes="**/${{ matrix.testClass }}.java" + MAX_RETRIES=3 + ATTEMPT=0 + EXIT_CODE=1 + while [ $ATTEMPT -lt $MAX_RETRIES ]; do + ATTEMPT=$((ATTEMPT + 1)) + echo "🔄 Attempt $ATTEMPT of $MAX_RETRIES..." + if mvn clean verify -P integration-tests -DtokenFlow=${{ matrix.tokenFlow }} -DtenancyModel=single -DskipUnitTests -Dfailsafe.includes="**/${{ matrix.testClass }}.java"; then + echo "✅ Tests passed on attempt $ATTEMPT!" + EXIT_CODE=0 + break + else + if [ $ATTEMPT -lt $MAX_RETRIES ]; then + echo "⚠️ Attempt $ATTEMPT failed. Retrying in 30 seconds..." + sleep 30 + else + echo "❌ All $MAX_RETRIES attempts failed for ${{ matrix.tokenFlow }} - ${{ matrix.testClass }}." + fi + fi + done + exit $EXIT_CODE diff --git a/.github/workflows/sonarqube.yml b/.github/workflows/sonarqube.yml index fb67c7044..fb8f0117e 100644 --- a/.github/workflows/sonarqube.yml +++ b/.github/workflows/sonarqube.yml @@ -16,6 +16,7 @@ permissions: jobs: sonar-scan: + environment: dev runs-on: ubuntu-latest steps: @@ -45,7 +46,12 @@ jobs: fi - name: Run SonarQube analysis + env: + SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: | + set +x + echo "::add-mask::$SONAR_TOKEN" if [ "${{ github.event_name }}" == "pull_request" ]; then sonar-scanner \ -Dsonar.projectKey=cap-java-sdm \ @@ -57,8 +63,8 @@ jobs: -Dsonar.inclusions=**/*.java \ -Dsonar.exclusions=**/target/**,**/node_modules/**,sdm/src/main/test/**,app/**/*.capnb,sdm/src/main/java/com/sap/cds/sdm/model/**,sdm/src/main/java/com/sap/cds/sdm/caching/CacheKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/RepoKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/TokenCacheKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/SecondaryTypesKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/SecondaryPropertiesKey.java \ -Dsonar.java.file.suffixes=.java \ - -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \ - -Dsonar.login=${{ secrets.SONAR_TOKEN }} \ + -Dsonar.host.url="$SONAR_HOST_URL" \ + -Dsonar.login="$SONAR_TOKEN" \ -Dsonar.pullrequest.key=${{ github.event.pull_request.number }} \ -Dsonar.pullrequest.branch=${{ github.head_ref }} \ -Dsonar.pullrequest.base=${{ github.base_ref }} @@ -73,8 +79,8 @@ jobs: -Dsonar.inclusions=**/*.java \ -Dsonar.exclusions=**/target/**,**/node_modules/**,sdm/src/main/test/**,app/**/*.capnb,sdm/src/main/java/com/sap/cds/sdm/model/**,sdm/src/main/java/com/sap/cds/sdm/caching/CacheKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/RepoKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/TokenCacheKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/SecondaryTypesKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/SecondaryPropertiesKey.java \ -Dsonar.java.file.suffixes=.java \ - -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \ - -Dsonar.login=${{ secrets.SONAR_TOKEN }} + -Dsonar.host.url="$SONAR_HOST_URL" \ + -Dsonar.login="$SONAR_TOKEN" fi - name: Quality Gate Check diff --git a/.github/workflows/unit.tests.yml b/.github/workflows/unit.tests.yml index 84c9b0016..10ad4074d 100644 --- a/.github/workflows/unit.tests.yml +++ b/.github/workflows/unit.tests.yml @@ -13,6 +13,7 @@ permissions: jobs: unitTests: + environment: dev runs-on: ubuntu-latest strategy: matrix: From 7614b78a4c676e592e08b28c526cbe6b503dc51a Mon Sep 17 00:00:00 2001 From: vibhutikumar <160819926+vibhutikumar07@users.noreply.github.com> Date: Fri, 5 Jun 2026 11:28:26 +0530 Subject: [PATCH 5/8] Update blackduck.yml --- .github/workflows/blackduck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/blackduck.yml b/.github/workflows/blackduck.yml index e4dde42c3..5561433c6 100644 --- a/.github/workflows/blackduck.yml +++ b/.github/workflows/blackduck.yml @@ -16,7 +16,7 @@ permissions: jobs: build: - environment: dev + # environment: dev runs-on: ubuntu-latest steps: - name: Checkout code From fa1704f9249ce1f80c08d7ad42a681f3877803d0 Mon Sep 17 00:00:00 2001 From: vibhutikumar <160819926+vibhutikumar07@users.noreply.github.com> Date: Fri, 5 Jun 2026 15:14:10 +0530 Subject: [PATCH 6/8] updated the workflow to use the pr environment & also added codeowner --- .github/CODEOWNERS | 3 +++ .github/workflows/blackduck.yml | 2 +- .github/workflows/sonarqube.yml | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..cd4a4af3c --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,3 @@ +# Workflow files — any change requires approval from one of the owners below +/.github/ @vibhutikumar07 @yashmeet29 +/.github/workflows/ @vibhutikumar07 @yashmeet29 \ No newline at end of file diff --git a/.github/workflows/blackduck.yml b/.github/workflows/blackduck.yml index 5561433c6..19b5e1cf4 100644 --- a/.github/workflows/blackduck.yml +++ b/.github/workflows/blackduck.yml @@ -16,7 +16,7 @@ permissions: jobs: build: - # environment: dev + environment: pr-analysis runs-on: ubuntu-latest steps: - name: Checkout code diff --git a/.github/workflows/sonarqube.yml b/.github/workflows/sonarqube.yml index fb8f0117e..4cbe4c055 100644 --- a/.github/workflows/sonarqube.yml +++ b/.github/workflows/sonarqube.yml @@ -16,7 +16,7 @@ permissions: jobs: sonar-scan: - environment: dev + environment: pr-analysis runs-on: ubuntu-latest steps: From 817498d3ae0d9bcbf44d996c1829728a5b9fa866 Mon Sep 17 00:00:00 2001 From: vibhutikumar <160819926+vibhutikumar07@users.noreply.github.com> Date: Fri, 5 Jun 2026 15:20:02 +0530 Subject: [PATCH 7/8] updated the workflow --- .github/workflows/codeql.yml | 1 - .github/workflows/pull-request-build.yml | 1 - .github/workflows/unit.tests.yml | 1 - 3 files changed, 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 5c6c0df5d..a5b5476e0 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -13,7 +13,6 @@ on: jobs: analyze: name: Analyze - environment: dev runs-on: ubuntu-latest permissions: diff --git a/.github/workflows/pull-request-build.yml b/.github/workflows/pull-request-build.yml index 9fa18c50a..38e0c6c40 100644 --- a/.github/workflows/pull-request-build.yml +++ b/.github/workflows/pull-request-build.yml @@ -11,7 +11,6 @@ on: jobs: build: - environment: dev runs-on: ubuntu-latest strategy: diff --git a/.github/workflows/unit.tests.yml b/.github/workflows/unit.tests.yml index 10ad4074d..84c9b0016 100644 --- a/.github/workflows/unit.tests.yml +++ b/.github/workflows/unit.tests.yml @@ -13,7 +13,6 @@ permissions: jobs: unitTests: - environment: dev runs-on: ubuntu-latest strategy: matrix: From 142179240cb1f53bf3bd8ccb92dd3274ce7c993d Mon Sep 17 00:00:00 2001 From: vibhutikumar <160819926+vibhutikumar07@users.noreply.github.com> Date: Fri, 5 Jun 2026 15:31:30 +0530 Subject: [PATCH 8/8] modified workflow --- .github/workflows/cfdeploy.yml | 2 -- .github/workflows/singleTenant_deploy_and_Integration_test.yml | 1 - .../singleTenant_deploy_and_Integration_test_LatestVersion.yml | 1 - 3 files changed, 4 deletions(-) diff --git a/.github/workflows/cfdeploy.yml b/.github/workflows/cfdeploy.yml index c352b8636..a5242aa8d 100644 --- a/.github/workflows/cfdeploy.yml +++ b/.github/workflows/cfdeploy.yml @@ -80,7 +80,6 @@ jobs: echo "::add-mask::$CF_ORG" echo "🔄 Preparing to deploy..." echo "Current Branch: 📂" - git branch pwd cd /home/runner/work/sdm/sdm/app/single-tenant/personal-space/demoapp/app echo "Changed to app directory 📂" @@ -214,7 +213,6 @@ jobs: echo "::add-mask::$CF_ORG" echo "🔄 Preparing to deploy..." echo "Current Branch: 📂" - git branch pwd cd /home/runner/work/sdm/sdm/app/single-tenant/central-space/demoapp diff --git a/.github/workflows/singleTenant_deploy_and_Integration_test.yml b/.github/workflows/singleTenant_deploy_and_Integration_test.yml index f62e5f3ee..b37c2bfdf 100644 --- a/.github/workflows/singleTenant_deploy_and_Integration_test.yml +++ b/.github/workflows/singleTenant_deploy_and_Integration_test.yml @@ -75,7 +75,6 @@ jobs: echo "::add-mask::$CF_ORG" echo "::add-mask::$CF_SPACE" echo "Current Branch......" - git branch pwd cd /home/runner/work/sdm/sdm/app/single-tenant/central-space/demoapp # Removing node_modules & package-lock.json diff --git a/.github/workflows/singleTenant_deploy_and_Integration_test_LatestVersion.yml b/.github/workflows/singleTenant_deploy_and_Integration_test_LatestVersion.yml index a4991ba6c..040bae71a 100644 --- a/.github/workflows/singleTenant_deploy_and_Integration_test_LatestVersion.yml +++ b/.github/workflows/singleTenant_deploy_and_Integration_test_LatestVersion.yml @@ -126,7 +126,6 @@ jobs: echo "::add-mask::$CF_ORG" echo "::add-mask::$CF_SPACE" echo "Current Branch......" - git branch pwd cd /home/runner/work/sdm/sdm/app/single-tenant/central-space/demoapp # Removing node_modules & package-lock.json