├── .reuse └── dep5 ├── .vscode └── settings.json ├── Jenkinsfile ├── LICENSE ├── LICENSES └── Apache-2.0.txt ├── README.md ├── approuter ├── .gitignore ├── manifest.yml ├── package-lock.json ├── package.json ├── ui │ ├── .editorconfig │ ├── .eslintignore │ ├── .eslintrc │ ├── .gitignore │ ├── .yo-rc.json │ ├── debug.log │ ├── karma-ci.conf.js │ ├── karma.conf.js │ ├── manifest.yaml │ ├── package-lock.json │ ├── package.json │ ├── readme.md │ └── uimodule │ │ ├── ui5.yaml │ │ └── webapp │ │ ├── Component.js │ │ ├── IMAGES │ │ ├── AD-1000.jpg │ │ ├── HT-1000.jpg │ │ ├── HT-1001.jpg │ │ ├── HT-1002.jpg │ │ ├── HT-1003.jpg │ │ ├── HT-1007.jpg │ │ ├── HT-1010.jpg │ │ ├── HT-1011.jpg │ │ ├── HT-1020.jpg │ │ ├── HT-1021.jpg │ │ ├── HT-1022.jpg │ │ ├── HT-1023.jpg │ │ ├── HT-1030.jpg │ │ ├── HT-1031.jpg │ │ ├── HT-1032.jpg │ │ ├── HT-1035.jpg │ │ ├── HT-1036.jpg │ │ ├── HT-1037.jpg │ │ ├── HT-1040.jpg │ │ ├── HT-1041.jpg │ │ ├── HT-1042.jpg │ │ ├── HT-1050.jpg │ │ ├── HT-1051.jpg │ │ ├── HT-1052.jpg │ │ ├── HT-1055.jpg │ │ ├── HT-1056.jpg │ │ ├── HT-1060.jpg │ │ ├── HT-1061.jpg │ │ ├── HT-1062.jpg │ │ ├── HT-1063.jpg │ │ ├── HT-1064.jpg │ │ ├── HT-1065.jpg │ │ ├── HT-1066.jpg │ │ ├── HT-1067.jpg │ │ ├── HT-1068.jpg │ │ ├── HT-1069.jpg │ │ ├── HT-1070.jpg │ │ ├── HT-1071.jpg │ │ ├── HT-1072.jpg │ │ ├── HT-1073.jpg │ │ ├── HT-1080.jpg │ │ ├── HT-1081.jpg │ │ ├── HT-1082.jpg │ │ ├── HT-1083.jpg │ │ ├── HT-1085.jpg │ │ ├── HT-1090.jpg │ │ ├── HT-1091.jpg │ │ ├── HT-1092.jpg │ │ ├── HT-1095.jpg │ │ ├── HT-1096.jpg │ │ ├── HT-1097.jpg │ │ ├── HT-1100.jpg │ │ ├── HT-1101.jpg │ │ ├── HT-1102.jpg │ │ ├── HT-1103.jpg │ │ ├── HT-1104.jpg │ │ ├── HT-1105.jpg │ │ ├── HT-1106.jpg │ │ ├── HT-1107.jpg │ │ ├── HT-1110.jpg │ │ ├── HT-1111.jpg │ │ ├── HT-1112.jpg │ │ ├── HT-1113.jpg │ │ ├── HT-1114.jpg │ │ ├── HT-1115.jpg │ │ ├── HT-1116.jpg │ │ ├── HT-1117.jpg │ │ ├── HT-1118.jpg │ │ ├── HT-1119.jpg │ │ ├── HT-1120.jpg │ │ ├── HT-1137.jpg │ │ ├── HT-1138.jpg │ │ ├── HT-1210.jpg │ │ ├── HT-1500.jpg │ │ ├── HT-1501.jpg │ │ ├── HT-1502.jpg │ │ ├── HT-1600.jpg │ │ ├── HT-1601.jpg │ │ ├── HT-1602.jpg │ │ ├── HT-1603.jpg │ │ ├── HT-2000.jpg │ │ ├── HT-2001.jpg │ │ ├── HT-2002.jpg │ │ ├── HT-2020.jpg │ │ ├── HT-2025.jpg │ │ ├── HT-2026.jpg │ │ ├── HT-2027.jpg │ │ ├── HT-2500.jpg │ │ ├── HT-2501.jpg │ │ ├── HT-2502.jpg │ │ ├── HT-6100.jpg │ │ ├── HT-6101.jpg │ │ ├── HT-6102.jpg │ │ ├── HT-6110.jpg │ │ ├── HT-6111.jpg │ │ ├── HT-6120.jpg │ │ ├── HT-6121.jpg │ │ ├── HT-6122.jpg │ │ ├── HT-6123.jpg │ │ ├── HT-6130.jpg │ │ ├── HT-6131.jpg │ │ ├── HT-6132.jpg │ │ ├── HT-7000.jpg │ │ ├── HT-7010.jpg │ │ ├── HT-7020.jpg │ │ ├── HT-7030.jpg │ │ ├── HT-8000.jpg │ │ ├── HT-8001.jpg │ │ ├── HT-8002.jpg │ │ ├── HT-8003.jpg │ │ ├── american.png │ │ ├── master.png │ │ ├── mastero.png │ │ └── resilience.png │ │ ├── controller │ │ ├── BaseController.js │ │ └── MainView.controller.js │ │ ├── css │ │ └── style.css │ │ ├── i18n │ │ ├── i18n.properties │ │ └── i18n_en.properties │ │ ├── index.html │ │ ├── manifest.json │ │ ├── model │ │ ├── countries.json │ │ ├── formatter.js │ │ └── models.js │ │ ├── resources │ │ └── img │ │ │ └── favicon.ico │ │ ├── test │ │ ├── integration │ │ │ ├── AllJourneys.js │ │ │ ├── BasicJourney.js │ │ │ ├── arrangements │ │ │ │ └── Startup.js │ │ │ ├── opaTests.qunit.html │ │ │ ├── opaTests.qunit.js │ │ │ └── pages │ │ │ │ └── MainView.js │ │ ├── testsuite.qunit.html │ │ └── testsuite.qunit.js │ │ └── view │ │ ├── MainView.view.xml │ │ ├── ReviewPage.fragment.xml │ │ └── orderView.fragment.xml └── xs-app.json ├── db ├── .gitignore ├── manifest.yaml ├── package-lock.json ├── package.json └── src │ ├── .hdiconfig │ ├── .hdinamespace │ └── data │ ├── FreightOrder.hdbtable │ ├── Products.hdbtable │ ├── Products.hdbtabledata │ ├── Stock.hdbtable │ ├── product.csv │ └── stocks.csv ├── freight-manager ├── .eslintrc.js ├── .gitignore ├── .npmrc ├── .prettierrc ├── manifest.yml ├── nest-cli.json ├── package-lock.json ├── package.json ├── sap-cloud-sdk-analytics.json ├── src │ ├── freight-service │ │ ├── freight.controller.spec.ts │ │ ├── freight.controller.ts │ │ ├── freight.module.ts │ │ └── freight.service.ts │ └── main.ts ├── systems.json ├── test │ ├── app.e2e-spec.ts │ └── jest-e2e.json ├── tsconfig.build.json ├── tsconfig.json └── xs-security.json ├── images ├── address-details.png ├── bullet.png ├── create-order.png ├── dbid.png ├── destination.png ├── env-logistics-service.png ├── hana-cockpit.png ├── hana.PNG ├── hr.gif ├── login page.png ├── nav-bg.gif ├── postman-token.png ├── request-quote.png ├── select-product.png ├── selected-product.png ├── shipment orders.png ├── solutiondiagram.PNG ├── solutiondiagram_updated.png ├── swagger-execute.png ├── swagger-post.png ├── swagger.png └── tam.PNG ├── logistics-service ├── .eslintrc.js ├── .gitignore ├── .npmrc ├── .prettierrc ├── manifest.yml ├── nest-cli.json ├── package-lock.json ├── package.json ├── sap-cloud-sdk-analytics.json ├── src │ ├── app.controller.spec.ts │ ├── app.controller.ts │ ├── app.module.ts │ ├── app.service.ts │ ├── logistics │ │ ├── order.controller.ts │ │ ├── order.module.ts │ │ ├── order.service.ts │ │ ├── quote.controller.ts │ │ ├── quote.module.ts │ │ └── quote.service.ts │ ├── main.ts │ ├── model │ │ └── quotemodel.dto.ts │ └── providers │ │ ├── destination.provider.ts │ │ └── security-credentials.provider.ts ├── systems.json ├── test │ ├── app.e2e-spec.ts │ └── jest-e2e.json ├── tsconfig.build.json └── tsconfig.json ├── product-service ├── .eslintrc.js ├── .gitignore ├── .npmrc ├── .prettierrc ├── manifest.yml ├── nest-cli.json ├── package-lock.json ├── package.json ├── sap-cloud-sdk-analytics.json ├── src │ ├── app.controller.ts │ ├── app.module.ts │ ├── app.service.ts │ ├── main.ts │ └── products │ │ ├── product.controller.ts │ │ ├── product.module.ts │ │ ├── product.service.ts │ │ ├── stock.controller.ts │ │ ├── stock.module.ts │ │ └── stock.service.ts ├── systems.json ├── test │ ├── app.controller.spec.ts │ ├── app.e2e-spec.ts │ └── jest-e2e.json ├── tsconfig.build.json └── tsconfig.json ├── security-config └── xs-security.json └── test ├── .gitignore ├── config.js ├── package.json ├── test-suite.js ├── test-suite.test.js └── util.js /.reuse/dep5: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: cloud-nodejs-oflm 3 | Upstream-Contact: Gopal Anand (gopal.anand@sap.com) 4 | Source: https://github.com/SAP-samples/cloud-nodejs-oflm 5 | 6 | Files: * 7 | Copyright: 2020 SAP SE or an SAP affiliate company and cloud-nodejs-oflm 8 | License: Apache-2.0 -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "git.ignoreLimitWarning": true, 3 | "SAP HANA Database Explorer.displaySapWebAnalyticsStartupNotification": false 4 | } -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env groovy 2 | @Library(['piper-lib', 'piper-lib-os']) _ 3 | stage ('Build') { 4 | node{ 5 | dockerExecuteOnKubernetes(script: this, dockerImage: 'ppiper/node-browsers:node12', dockerWorkspace: '/home/node') { 6 | sh ''' 7 | rm -rf outbound-freight-and-logistics-management 8 | git -c http.sslVerify=false clone https://github.tools.sap/BTP-E2EScenarioValidation/outbound-freight-and-logistics-management.git 9 | cd outbound-freight-and-logistics-management 10 | cd freight-manager 11 | npm i 12 | npm run build 13 | cd .. 14 | pwd 15 | cd logistics-service 16 | npm i 17 | npm run build 18 | cd .. 19 | cd product-service 20 | npm i 21 | npm run build 22 | 23 | 24 | ''' 25 | } 26 | } 27 | } 28 | stage ('deploy') { 29 | node{ 30 | dockerExecuteOnKubernetes(script: this, dockerImage: 'docker.wdf.sap.corp:51010/sfext:latest', dockerWorkspace: '/home/node') { 31 | sh ''' 32 | cf login -u $nodeappuser -p $nodeappwd -a $nodeappurl -o $nodeapporg -s $nodeappspace 33 | cd outbound-freight-and-logistics-management 34 | cd freight-manager 35 | npm run deploy 36 | cd .. 37 | cd product-service 38 | npm run deploy 39 | cd .. 40 | cd logistics-service 41 | ls 42 | rm -rf dist 43 | rm -rf deployment 44 | rm -rf package-lock.json 45 | ls 46 | npm run deploy 47 | 48 | 49 | ''' 50 | } 51 | } 52 | } 53 | stage ('test') { 54 | node(){ 55 | dockerExecuteOnKubernetes(script: this,dockerEnvVars: ['pusername':pusername, 'puserpwd':puserpwd], dockerImage: 'docker.wdf.sap.corp:51010/sfext:latest', dockerWorkspace: '/home/node') { 56 | sh ''' 57 | cf login -u $nodeappuser -p $nodeappwd -a $nodeappurl -o $nodeapporg -s $nodeappspace 58 | logistics_guid=`cf app logistics-service --guid` 59 | echo $logistics_guid 60 | product_guid=`cf app product-service --guid` 61 | echo $product_guid 62 | freight_guid=`cf app freight-manager --guid` 63 | echo $freight_guid 64 | cd outbound-freight-and-logistics-management 65 | cd test 66 | npm i 67 | cf curl /v2/apps/$logistics_guid/env > logistic_env.json 68 | cf curl /v2/apps/$product_guid/env > product_env.json 69 | cf curl /v2/apps/$freight_guid/env > freight_env.json 70 | ls 71 | jest ./test 72 | 73 | 74 | ''' 75 | } 76 | } 77 | } 78 | 79 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2021 SAP 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSES/Apache-2.0.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. 9 | 10 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. 11 | 12 | "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. 13 | 14 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. 15 | 16 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. 17 | 18 | "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. 19 | 20 | "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). 21 | 22 | "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. 23 | 24 | "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." 25 | 26 | "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. 27 | 28 | 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. 29 | 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. 30 | 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: 31 | (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and 32 | (b) You must cause any modified files to carry prominent notices stating that You changed the files; and 33 | (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 34 | (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. 35 | 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. 36 | 37 | 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. 38 | 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. 39 | 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. 40 | 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. 41 | 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. 42 | END OF TERMS AND CONDITIONS 43 | 44 | APPENDIX: How to apply the Apache License to your work. 45 | 46 | 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. 47 | 48 | Copyright 2020 SAP SE 49 | 50 | Licensed under the Apache License, Version 2.0 (the "License"); 51 | you may not use this file except in compliance with the License. 52 | You may obtain a copy of the License at 53 | 54 | http://www.apache.org/licenses/LICENSE-2.0 55 | 56 | Unless required by applicable law or agreed to in writing, software 57 | distributed under the License is distributed on an "AS IS" BASIS, 58 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 59 | See the License for the specific language governing permissions and 60 | limitations under the License. -------------------------------------------------------------------------------- /approuter/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | -------------------------------------------------------------------------------- /approuter/manifest.yml: -------------------------------------------------------------------------------- 1 | applications: 2 | - name: oflm-approuter 3 | path: . 4 | memory: 128M 5 | buildpacks: 6 | - nodejs_buildpack 7 | env: 8 | TENANT_HOST_PATTERN: >- 9 | "oflm-approuter-(.*).cfapps.eu10-004.hana.ondemand.com" 10 | destinations: >- 11 | [ 12 | {"name": "product-service","url": "https://product-service-zany-wallaby-ns.cfapps.eu10-004.hana.ondemand.com", "forwardAuthToken":true}, 13 | {"name": "logisticsService","url":"https://logistics-service-exhausted-gnu-bs.cfapps.eu10-004.hana.ondemand.com", "forwardAuthToken":true} 14 | ] 15 | services: 16 | - businessuser-authentication 17 | -------------------------------------------------------------------------------- /approuter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "approuter", 3 | "dependencies": { 4 | "@sap/approuter": "^14.4.3" 5 | }, 6 | "scripts": { 7 | "start": "node node_modules/@sap/approuter/approuter.js" 8 | } 9 | } -------------------------------------------------------------------------------- /approuter/ui/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | end_of_line = lf 10 | # editorconfig-tools is unable to ignore longs strings or urls 11 | max_line_length = off -------------------------------------------------------------------------------- /approuter/ui/.eslintignore: -------------------------------------------------------------------------------- 1 | templates/ 2 | deployer/resources/ 3 | node_modules/ 4 | approuter/webapp/ 5 | -------------------------------------------------------------------------------- /approuter/ui/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true 4 | }, 5 | "parserOptions": { 6 | "ecmaVersion": 2019 7 | }, 8 | "globals": { 9 | "sap": true, 10 | "jQuery": true 11 | }, 12 | "rules": { 13 | "block-scoped-var": 1, 14 | "keyword-spacing": 2, 15 | "space-unary-ops": 2, 16 | "camelcase": 1, 17 | "consistent-return": 1, 18 | "no-warning-comments": 1, 19 | "default-case": 1, 20 | "no-console": 2, 21 | "no-unused-vars": 2, 22 | "no-trailing-spaces": 2, 23 | "no-debugger": 2, 24 | "semi": [ 25 | 1, 26 | "always" 27 | ], 28 | "quotes": [ 29 | 1, 30 | "double" 31 | ], 32 | "key-spacing": [ 33 | 1, 34 | { 35 | "beforeColon": false 36 | } 37 | ], 38 | "comma-spacing": [ 39 | 1, 40 | { 41 | "before": false, 42 | "after": true 43 | } 44 | ], 45 | "no-shadow": 2, 46 | "no-irregular-whitespace": 2 47 | } 48 | } -------------------------------------------------------------------------------- /approuter/ui/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | 3 | /node_modules 4 | -------------------------------------------------------------------------------- /approuter/ui/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-easy-ui5": { 3 | "projectname": "oflm", 4 | "namespace": "com.sap", 5 | "platform": "Static webserver", 6 | "viewtype": "XML", 7 | "viewname": "MainView", 8 | "ui5libs": "Content delivery network (SAPUI5)", 9 | "newdir": false, 10 | "namespaceURI": "com/sap", 11 | "uimodules": [ 12 | "uimodule" 13 | ], 14 | "setupCompleted": true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /approuter/ui/debug.log: -------------------------------------------------------------------------------- 1 | [0730/130359.410:ERROR:crash_report_database_win.cc(428)] unexpected header 2 | [0813/130757.206:ERROR:crash_report_database_win.cc(428)] unexpected header 3 | [0813/140421.871:ERROR:crash_report_database_win.cc(428)] unexpected header 4 | -------------------------------------------------------------------------------- /approuter/ui/karma-ci.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function (config) { 2 | "use strict"; 3 | 4 | require("./karma.conf")(config); 5 | config.set({ 6 | 7 | // test results reporter to use 8 | // possible values: "dots", "progress", "coverage" 9 | reporters: ["progress"], 10 | 11 | // start these browsers 12 | browsers: ["ChromeHeadless"], 13 | 14 | // Continuous Integration mode 15 | // if true, Karma captures browsers, runs the tests and exits 16 | singleRun: true 17 | 18 | }); 19 | }; 20 | -------------------------------------------------------------------------------- /approuter/ui/karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function (config) { 2 | "use strict"; 3 | 4 | config.set({ 5 | frameworks: ["ui5"], ui5: { 6 | type: "application", 7 | configPath: "uimodule/ui5.yaml", 8 | paths: { 9 | webapp: "uimodule/webapp" 10 | } 11 | }, 12 | browsers: ["Chrome"], 13 | browserConsoleLogOptions: { 14 | level: "error" 15 | } 16 | }); 17 | }; 18 | -------------------------------------------------------------------------------- /approuter/ui/manifest.yaml: -------------------------------------------------------------------------------- 1 | applications: 2 | - name: oflm 3 | path: uimodule/ 4 | buildpacks: 5 | - staticfile_buildpack 6 | memory: 64M 7 | -------------------------------------------------------------------------------- /approuter/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "oflm", 3 | "version": "0.0.1", 4 | "scripts": { 5 | "start": "ui5 serve --config=uimodule/ui5.yaml --open index.html", 6 | "build:ui": "run-s build:uimodule", 7 | "test": "run-s lint karma", 8 | "karma-ci": "karma start karma-ci.conf.js", 9 | "clearCoverage": "shx rm -rf coverage", 10 | "karma": "run-s clearCoverage karma-ci", 11 | "lint": "eslint .", 12 | "serve:uimodule": "ui5 serve --config=uimodule/ui5.yaml", 13 | "build:uimodule": "ui5 build --config=uimodule/ui5.yaml --clean-dest --dest uimodule/dist --include-task=generateManifestBundle" 14 | }, 15 | "devDependencies": { 16 | "@ui5/cli": "^3.0.7", 17 | "decode-uri-component": ">=0.2.1", 18 | "eslint": "^8.10.0", 19 | "karma": "^6.3.17", 20 | "karma-chrome-launcher": "^3.1.1", 21 | "karma-coverage": "^2.2.0", 22 | "karma-ui5": "^3.0.2", 23 | "npm-run-all": "^4.1.5", 24 | "shx": "^0.3.4", 25 | "ui5-middleware-livereload": "^0.5.9" 26 | }, 27 | "ui5": { 28 | "dependencies": [ 29 | "ui5-middleware-livereload" 30 | ] 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /approuter/ui/readme.md: -------------------------------------------------------------------------------- 1 | # oflm 2 | Insert the purpose of this project and some intersting infos here 3 | 4 | 5 | ## Credits 6 | This project has been generated with 💙 and [easy-ui5](https://github.com/SAP) 7 | -------------------------------------------------------------------------------- /approuter/ui/uimodule/ui5.yaml: -------------------------------------------------------------------------------- 1 | specVersion: "2.0" 2 | metadata: 3 | name: oflm_uimodule 4 | type: application 5 | resources: 6 | configuration: 7 | paths: 8 | webapp: uimodule/webapp 9 | framework: 10 | name: SAPUI5 11 | version: 1.77.0 12 | libraries: 13 | - name: sap.ui.core 14 | - name: sap.m 15 | - name: sap.ui.layout 16 | - name: themelib_sap_fiori_3 17 | server: 18 | customMiddleware: 19 | - name: ui5-middleware-livereload 20 | afterMiddleware: compression 21 | configuration: 22 | port: 35729 23 | path: uimodule/webapp 24 | -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/Component.js: -------------------------------------------------------------------------------- 1 | sap.ui.define([ 2 | "sap/ui/core/UIComponent", 3 | "sap/ui/Device", 4 | "com/sap/oflm/model/models" 5 | ], function(UIComponent, Device, models) { 6 | "use strict"; 7 | 8 | return UIComponent.extend("com.sap.oflm.Component", { 9 | 10 | metadata: { 11 | manifest: "json" 12 | }, 13 | 14 | /** 15 | * The component is initialized by UI5 automatically during the startup of the app and calls the init method once. 16 | * @public 17 | * @override 18 | */ 19 | init: function() { 20 | // call the base component's init function 21 | UIComponent.prototype.init.apply(this, arguments); 22 | 23 | // enable routing 24 | this.getRouter().initialize(); 25 | 26 | // set the device model 27 | this.setModel(models.createDeviceModel(), "device"); 28 | } 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/AD-1000.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/AD-1000.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1000.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1000.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1001.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1002.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1002.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1003.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1003.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1007.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1007.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1010.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1010.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1011.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1011.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1020.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1020.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1021.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1021.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1022.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1022.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1023.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1023.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1030.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1030.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1031.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1031.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1032.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1032.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1035.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1035.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1036.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1036.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1037.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1037.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1040.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1040.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1041.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1041.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1042.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1042.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1050.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1050.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1051.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1051.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1052.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1052.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1055.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1055.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1056.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1056.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1060.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1060.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1061.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1061.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1062.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1062.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1063.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1063.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1064.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1064.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1065.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1065.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1066.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1066.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1067.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1067.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1068.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1068.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1069.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1069.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1070.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1070.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1071.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1071.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1072.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1072.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1073.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1073.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1080.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1080.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1081.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1081.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1082.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1082.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1083.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1083.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1085.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1085.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1090.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1090.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1091.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1091.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1092.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1092.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1095.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1095.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1096.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1096.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1097.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1097.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1100.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1100.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1101.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1101.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1102.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1102.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1103.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1103.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1104.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1104.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1105.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1105.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1106.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1106.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1107.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1107.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1110.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1110.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1111.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1111.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1112.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1112.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1113.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1113.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1114.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1114.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1115.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1115.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1116.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1116.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1117.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1117.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1118.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1118.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1119.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1119.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1120.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1120.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1137.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1137.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1138.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1138.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1210.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1210.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1500.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1500.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1501.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1501.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1502.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1502.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1600.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1600.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1601.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1601.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1602.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1602.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-1603.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-1603.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-2000.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-2000.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-2001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-2001.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-2002.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-2002.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-2020.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-2020.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-2025.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-2025.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-2026.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-2026.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-2027.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-2027.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-2500.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-2500.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-2501.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-2501.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-2502.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-2502.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-6100.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-6100.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-6101.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-6101.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-6102.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-6102.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-6110.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-6110.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-6111.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-6111.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-6120.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-6120.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-6121.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-6121.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-6122.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-6122.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-6123.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-6123.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-6130.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-6130.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-6131.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-6131.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-6132.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-6132.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-7000.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-7000.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-7010.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-7010.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-7020.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-7020.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-7030.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-7030.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-8000.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-8000.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-8001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-8001.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-8002.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-8002.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/HT-8003.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/HT-8003.jpg -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/american.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/american.png -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/master.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/master.png -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/mastero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/mastero.png -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/IMAGES/resilience.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/IMAGES/resilience.png -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/controller/BaseController.js: -------------------------------------------------------------------------------- 1 | sap.ui.define([ 2 | "sap/ui/core/mvc/Controller", 3 | "sap/ui/core/routing/History", 4 | "sap/ui/core/UIComponent", 5 | "com/sap/oflm/model/formatter" 6 | ], function(Controller, History, UIComponent, formatter) { 7 | "use strict"; 8 | 9 | return Controller.extend("com.sap.oflm.controller.BaseController", { 10 | 11 | formatter: formatter, 12 | 13 | /** 14 | * Convenience method for getting the view model by name in every controller of the application. 15 | * @public 16 | * @param {string} sName the model name 17 | * @returns {sap.ui.model.Model} the model instance 18 | */ 19 | getModel: function(sName) { 20 | return this.getView().getModel(sName); 21 | }, 22 | 23 | /** 24 | * Convenience method for setting the view model in every controller of the application. 25 | * @public 26 | * @param {sap.ui.model.Model} oModel the model instance 27 | * @param {string} sName the model name 28 | * @returns {sap.ui.mvc.View} the view instance 29 | */ 30 | setModel: function(oModel, sName) { 31 | return this.getView().setModel(oModel, sName); 32 | }, 33 | 34 | /** 35 | * Convenience method for getting the resource bundle. 36 | * @public 37 | * @returns {sap.ui.model.resource.ResourceModel} the resourceModel of the component 38 | */ 39 | getResourceBundle: function() { 40 | return this.getOwnerComponent().getModel("i18n").getResourceBundle(); 41 | }, 42 | 43 | /** 44 | * Method for navigation to specific view 45 | * @public 46 | * @param {string} psTarget Parameter containing the string for the target navigation 47 | * @param {mapping} pmParameters? Parameters for navigation 48 | * @param {boolean} pbReplace? Defines if the hash should be replaced (no browser history entry) or set (browser history entry) 49 | */ 50 | navTo: function(psTarget, pmParameters, pbReplace) { 51 | this.getRouter().navTo(psTarget, pmParameters, pbReplace); 52 | }, 53 | 54 | getRouter: function() { 55 | return UIComponent.getRouterFor(this); 56 | }, 57 | 58 | onNavBack: function() { 59 | var sPreviousHash = History.getInstance().getPreviousHash(); 60 | 61 | if (sPreviousHash !== undefined) { 62 | window.history.back(); 63 | } else { 64 | this.getRouter().navTo("appHome", {}, true /*no history*/ ); 65 | } 66 | } 67 | 68 | }); 69 | 70 | }); 71 | -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/css/style.css: -------------------------------------------------------------------------------- 1 | /* Enter your custom styles here */ 2 | -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/i18n/i18n.properties: -------------------------------------------------------------------------------- 1 | title=Outbound Freight and Logistics Management 2 | appTitle=Outbound Freight and Logistics Management 3 | appDescription=Outbound Freight and Logistics Management 4 | -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/i18n/i18n_en.properties: -------------------------------------------------------------------------------- 1 | title=Outbound Freight and Logistics Management 2 | appTitle=Outbound Freight and Logistics Management 3 | appDescription=Outbound Freight and Logistics Management 4 | -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | oflm 11 | 12 | 18 | 19 | 20 | 21 |
23 |
24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "_version": "1.12.0", 3 | "sap.app": { 4 | "id": "com.sap.oflm", 5 | "type": "application", 6 | "i18n": "i18n/i18n.properties", 7 | "applicationVersion": { 8 | "version": "1.0.0" 9 | }, 10 | "title": "{{appTitle}}", 11 | "description": "{{appDescription}}" 12 | }, 13 | "sap.ui": { 14 | "technology": "UI5", 15 | "icons": { 16 | "icon": "", 17 | "favIcon": "", 18 | "phone": "", 19 | "phone@2": "", 20 | "tablet": "", 21 | "tablet@2": "" 22 | }, 23 | "deviceTypes": { 24 | "desktop": true, 25 | "tablet": true, 26 | "phone": true 27 | } 28 | }, 29 | "sap.ui5": { 30 | "rootView": { 31 | "viewName": "com.sap.oflm.view.MainView", 32 | "type": "XML", 33 | "async": true, 34 | "id": "idAppControl" 35 | }, 36 | "dependencies": { 37 | "minUI5Version": "1.60.0", 38 | "libs": { 39 | "sap.ui.core": {}, 40 | "sap.m": {}, 41 | "sap.ui.layout": {} 42 | } 43 | }, 44 | "contentDensities": { 45 | "compact": true, 46 | "cozy": true 47 | }, 48 | "models": { 49 | "i18n": { 50 | "type": "sap.ui.model.resource.ResourceModel", 51 | "settings": { 52 | "bundleName": "com.sap.oflm.i18n.i18n" 53 | } 54 | } 55 | }, 56 | "resources": { 57 | "css": [ 58 | { 59 | "uri": "css/style.css" 60 | } 61 | ] 62 | }, 63 | "routing": { 64 | "config": { 65 | "routerClass": "sap.m.routing.Router", 66 | "viewType": "XML", 67 | "viewPath": "com.sap.oflm.view", 68 | "controlId": "idAppControl", 69 | "controlAggregation": "pages", 70 | "async": true 71 | }, 72 | "routes": [ 73 | { 74 | "name": "RouteMainView", 75 | "pattern": "RouteMainView", 76 | "target": [ 77 | "TargetMainView" 78 | ] 79 | } 80 | ], 81 | "targets": { 82 | "TargetMainView": { 83 | "viewType": "XML", 84 | "viewLevel": 1, 85 | "viewId": "idAppControl", 86 | "viewName": "MainView" 87 | } 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/model/formatter.js: -------------------------------------------------------------------------------- 1 | sap.ui.define([], function () { 2 | "use strict"; 3 | return { 4 | dateFormatter: function (date) { 5 | return new Date(date.slice(0, 4) + "/" + date.slice(4, 6) + "/" + date.slice(6, 8)).toDateString(); 6 | }, 7 | statusFormatter: function (state) { 8 | var status; 9 | if (state === "A") { 10 | status = "Accepted"; 11 | } else { 12 | status = "Declined"; 13 | } 14 | return status; 15 | } 16 | }; 17 | }); 18 | -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/model/models.js: -------------------------------------------------------------------------------- 1 | sap.ui.define([ 2 | "sap/ui/model/json/JSONModel", 3 | "sap/ui/Device" 4 | ], function(JSONModel, Device) { 5 | "use strict"; 6 | 7 | return { 8 | createDeviceModel: function() { 9 | var oModel = new JSONModel(Device); 10 | oModel.setDefaultBindingMode("OneWay"); 11 | return oModel; 12 | } 13 | }; 14 | }); 15 | -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/resources/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/approuter/ui/uimodule/webapp/resources/img/favicon.ico -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/test/integration/AllJourneys.js: -------------------------------------------------------------------------------- 1 | sap.ui.define([ 2 | "sap/ui/test/Opa5", 3 | "com/sap/oflm/test/integration/arrangements/Startup", 4 | "com/sap/oflm/test/integration/BasicJourney" 5 | ], function(Opa5, Startup) { 6 | "use strict"; 7 | 8 | Opa5.extendConfig({ 9 | arrangements: new Startup(), 10 | pollingInterval: 1 11 | }); 12 | 13 | }); 14 | -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/test/integration/BasicJourney.js: -------------------------------------------------------------------------------- 1 | sap.ui.define([ 2 | "sap/ui/test/opaQunit", 3 | "com/sap/oflm/test/integration/pages/MainView" 4 | ], function (opaTest) { 5 | "use strict"; 6 | 7 | opaTest("should show correct number of nested pages", function (Given, When, Then) { 8 | 9 | // Arrangements 10 | Given.iStartMyApp(); 11 | 12 | // Assertions 13 | Then.onTheAppPage.iShouldSeePageCount(1); 14 | 15 | // Cleanup 16 | Then.iTeardownMyApp(); 17 | }); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/test/integration/arrangements/Startup.js: -------------------------------------------------------------------------------- 1 | sap.ui.define([ 2 | "sap/ui/test/Opa5" 3 | ], function(Opa5) { 4 | "use strict"; 5 | 6 | return Opa5.extend("com.sap.oflm.test.integration.arrangements.Startup", { 7 | 8 | iStartMyApp: function () { 9 | this.iStartMyUIComponent({ 10 | componentConfig: { 11 | name: "com.sap.oflm", 12 | async: true, 13 | manifest: true 14 | } 15 | }); 16 | } 17 | 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/test/integration/opaTests.qunit.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Integration tests for Todo App 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/test/integration/opaTests.qunit.js: -------------------------------------------------------------------------------- 1 | /* global QUnit */ 2 | 3 | QUnit.config.autostart = false; 4 | 5 | sap.ui.getCore().attachInit(function() { 6 | "use strict"; 7 | 8 | sap.ui.require([ 9 | "com/sap/oflm/test/integration/AllJourneys" 10 | ], function() { 11 | QUnit.start(); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/test/integration/pages/MainView.js: -------------------------------------------------------------------------------- 1 | sap.ui.require([ 2 | "sap/ui/test/Opa5", 3 | "sap/ui/test/matchers/AggregationLengthEquals" 4 | ], function (Opa5, AggregationLengthEquals) { 5 | "use strict"; 6 | 7 | var sViewName = "com.sap.oflm.view.MainView"; 8 | var sAppId = "idAppControl"; 9 | 10 | Opa5.createPageObjects({ 11 | onTheAppPage: { 12 | 13 | assertions: { 14 | 15 | iShouldSeePageCount: function(iItemCount) { 16 | return this.waitFor({ 17 | id: sAppId, 18 | viewName: sViewName, 19 | matchers: [new AggregationLengthEquals({ 20 | name: "pages", 21 | length: iItemCount 22 | })], 23 | success: function() { 24 | Opa5.assert.ok(true, "The app contains one page"); 25 | }, 26 | errorMessage: "App does not have expected number of pages '" + iItemCount + "'." 27 | }); 28 | } 29 | } 30 | 31 | } 32 | }); 33 | 34 | }); 35 | -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/test/testsuite.qunit.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | QUnit test suite for Worklist 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/test/testsuite.qunit.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line 2 | window.suite = function() { 3 | "use strict"; 4 | 5 | // eslint-disable-next-line 6 | var oSuite = new parent.jsUnitTestSuite(), 7 | sContextPath = location.pathname.substring(0, location.pathname.lastIndexOf("/") + 1); 8 | 9 | oSuite.addTestPage(sContextPath + "integration/opaTests.qunit.html"); 10 | 11 | return oSuite; 12 | }; 13 | -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/view/MainView.view.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | <ToolbarSpacer /> 11 | <Button icon="sap-icon://add" press="createNewOrder" /> 12 | </OverflowToolbar> 13 | </headerToolbar> 14 | <ObjectListItem title="{ordersModel>PRODUCTNAME}" type="Inactive" number="{ 15 | parts:[{path:'ordersModel>TRANSPORTATIONCHARGES'}], 16 | formatOptions: {showMeasure: false} 17 | }" numberUnit="{ordersModel>CURRENCYCODE}"> 18 | <firstStatus> 19 | <ObjectStatus text="{ 20 | path: 'ordersModel>LIFECYCLESTATUSCODE', 21 | formatter: '.formatter.statusFormatter'}" state="Success" /> 22 | </firstStatus> 23 | <ObjectAttribute text="Order ID- {ordersModel>ID}" /> 24 | <ObjectAttribute text="Created on- { 25 | path: 'ordersModel>DELIVERYDATE', 26 | formatter: '.formatter.dateFormatter'}" /> 27 | <ObjectAttribute text="Weight- {ordersModel>GROSSWEIGHT} KG" /> 28 | <ObjectAttribute text="Created by- {ordersModel>CREATED_BY}" /> 29 | </ObjectListItem> 30 | </List> 31 | </content> 32 | </Page> 33 | </pages> 34 | </App> 35 | </mvc:View> -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/view/ReviewPage.fragment.xml: -------------------------------------------------------------------------------- 1 | <core:FragmentDefinition 2 | height="100%" 3 | xmlns:f="sap.ui.layout.form" 4 | xmlns:l="sap.ui.layout" 5 | xmlns:core="sap.ui.core" 6 | xmlns="sap.m"> 7 | <Page id="wizardReviewPage" showHeader="false"> 8 | <content> 9 | <ObjectHeader id="selectedProductObjectReview" icon="{productListModel>PICTUREURL}" iconDensityAware="false" iconAlt="{productListModel>PRODUCTNAME}" title="{productListModel>PRODUCTNAME}" number="{ 10 | parts:[{path:'productListModel>PRICE'}], 11 | type: 'sap.ui.model.type.Currency', 12 | formatOptions: {showMeasure: false} 13 | }" class="sapUiResponsivePadding--header" numberUnit="EUR"> 14 | <ObjectAttribute text="{productListModel>WEIGHT} {productListModel>WEIGHTUNIT}" /> 15 | <ObjectAttribute text="{productListModel>DIMENSIONWIDTH} x {productListModel>DIMENSIONDEPTH} x {productListModel>DIMENSIONHEIGHT} {productListModel>DIMENSIONUNIT}" /> 16 | <ObjectAttribute text="{productListModel>SHORTDESCRIPTION}" /> 17 | </ObjectHeader> 18 | <HBox alignItems="Center"> 19 | <Label text="Quantity:" class="sapUiSmallMargin"/> 20 | <Text id="reviewQuanitity" class="sapUiTinyMarginBegin"/> 21 | </HBox> 22 | <f:SimpleForm id="addressForm" editable="true" layout="ResponsiveGridLayout" title="Delivery Details" labelSpanXL="3" labelSpanL="3" labelSpanM="3" labelSpanS="12" adjustLabelSpan="false" emptySpanXL="4" emptySpanL="4" emptySpanM="4" emptySpanS="0" columnsXL="1" columnsL="1" columnsM="1" singleContainerFullSize="false"> 23 | <f:content> 24 | <Label text="Contact Person" /> 25 | <Text text="{shipmentModel>/person}" /> 26 | <Label text="Street" /> 27 | <Text text="{shipmentModel>/street}"/> 28 | <Label text="Street Number" /> 29 | <Text text="{shipmentModel>/house}"> 30 | </Text> 31 | <Label text="Phone, Email" /> 32 | <Text text="{shipmentModel>/phone}" /> 33 | <Label text="Email" /> 34 | <Text text="{ 35 | path : 'shipmentModel>/email' 36 | }" /> 37 | <Label text="Country/Region"/> 38 | <Text text="{shipmentModel>/country}"/> 39 | <!-- <Button text="Create Order" press="onCreateOrder" type="Accept"></Button> --> 40 | </f:content> 41 | </f:SimpleForm> 42 | </content> 43 | <footer> 44 | <Bar> 45 | <contentRight> 46 | <Button text="Submit" press="submitData"/> 47 | <Button text="Cancel" press="closeDialog"/> 48 | </contentRight> 49 | </Bar> 50 | </footer> 51 | </Page> 52 | </core:FragmentDefinition> 53 | -------------------------------------------------------------------------------- /approuter/ui/uimodule/webapp/view/orderView.fragment.xml: -------------------------------------------------------------------------------- 1 | <core:FragmentDefinition xmlns="sap.m" xmlns:f="sap.ui.layout.form" xmlns:u="sap.ui.unified" xmlns:l="sap.ui.layout" xmlns:core="sap.ui.core"> 2 | <Dialog id="orderDialog" title="Create Order" showHeader="false" stretch="true" > 3 | <subHeader> 4 | <Toolbar> 5 | <ToolbarSpacer/> 6 | <Title text="Create Order" level="H3"/> 7 | <ToolbarSpacer/> 8 | <Button press="closeDialog" icon="sap-icon://decline"></Button> 9 | </Toolbar> 10 | </subHeader> 11 | <NavContainer id="wizardNavContainer"> 12 | <Wizard id="createOrderWizard" class="sapUiResponsivePadding--header sapUiResponsivePadding--content" complete="onCreateOrder"> 13 | <WizardStep id="ProductTypeStep" title="Select Product" validated="false"> 14 | <Label text="Select Product" class="sapUiSmallMargin"></Label> 15 | <Select items="{ 16 | path: 'productListModel>/', 17 | sorter: { path: 'PRODUCTNAME' } 18 | }" id="productListSelection" change="productSelected"> 19 | <core:Item text="{productListModel>PRODUCTNAME}" key="{productListModel>PRODUCTID}"></core:Item> 20 | </Select> 21 | </WizardStep> 22 | <WizardStep id="quoteStep" validated="false" title="Request Quote" activate="additionalInfoValidation"> 23 | <ObjectHeader id="selectedProductObject" icon="{productListModel>PICTUREURL}" iconDensityAware="false" iconAlt="{productListModel>PRODUCTNAME}" title="{productListModel>PRODUCTNAME}" number="{ 24 | parts:[{path:'productListModel>PRICE'}], 25 | type: 'sap.ui.model.type.Currency', 26 | formatOptions: {showMeasure: false} 27 | }" class="sapUiResponsivePadding--header" numberUnit="EUR"> 28 | <ObjectAttribute text="{productListModel>WEIGHT} {productListModel>WEIGHTUNIT}" /> 29 | <ObjectAttribute text="{productListModel>DIMENSIONWIDTH} x {productListModel>DIMENSIONDEPTH} x {productListModel>DIMENSIONHEIGHT} {productListModel>DIMENSIONUNIT}" /> 30 | <ObjectAttribute text="{productListModel>SHORTDESCRIPTION}" /> 31 | </ObjectHeader> 32 | <f:SimpleForm editable="true" layout="ResponsiveGridLayout" labelSpanXL="3" labelSpanL="3" labelSpanM="3" labelSpanS="12" adjustLabelSpan="false" emptySpanXL="4" emptySpanL="4" emptySpanM="4" emptySpanS="0" columnsXL="1" columnsL="1" columnsM="1" singleContainerFullSize="false"> 33 | <f:content> 34 | 35 | <Label text="Quantity" required="true" /> 36 | <Input type="Number" width="5rem" id="quantityId"></Input> 37 | <Label text="Distance" required="true" /> 38 | <Input type="Number" description="KM" width="10rem" id="distanceId"></Input> 39 | <Label text="Mode" required="true" /> 40 | <ComboBox id="transportationMeans"> 41 | <core:Item key="AIR" text="AIR" /> 42 | <core:Item key="RAIL" text="RAIL" /> 43 | <core:Item key="ROAD" text="ROAD" /> 44 | <core:Item key="SHIP" text="SHIP" /> 45 | </ComboBox> 46 | <Button type="Emphasized" text="Request Quote" press="onRequestQuote"></Button> 47 | </f:content> 48 | </f:SimpleForm> 49 | <VBox id="quoteBox" visible="false" alignItems="Start"> 50 | <Label text="Quote Price: " class="sapUiSmallMarginBegin"/> 51 | <ObjectNumber class="sapMObjectNumberLarge" id="quotePrice" unit="EUR" emphasized="false" state="None" /> 52 | </VBox> 53 | </WizardStep> 54 | <WizardStep id="OptionalInfoStep" validated="true" title="Shipment Information"> 55 | <VBox class="sapUiSmallMargin"> 56 | <f:SimpleForm id="addressForm" editable="true" layout="ResponsiveGridLayout" title="Delivery Details" labelSpanXL="3" labelSpanL="3" labelSpanM="3" labelSpanS="12" adjustLabelSpan="false" emptySpanXL="4" emptySpanL="4" emptySpanM="4" emptySpanS="0" columnsXL="1" columnsL="1" columnsM="1" singleContainerFullSize="false"> 57 | <f:content> 58 | <Label text="Contact Person" required="true" /> 59 | <Input id="name" value="{shipmentModel>/person}" /> 60 | <Label text="Street/No." /> 61 | <Input id="street" value="{shipmentModel>/street}"></Input> 62 | <Input id="houseNumber" value="{shipmentModel>/house}"> 63 | <layoutData> 64 | <l:GridData span="XL1 L2 M2 S4" /> 65 | </layoutData> 66 | </Input> 67 | <Label text="Phone, Email" required="true" /> 68 | <Input value="{shipmentModel>/phone}" id="mobile" maxLength="10" type="Number"> 69 | <layoutData> 70 | <l:GridData span="XL1 L2 M2 S4" /> 71 | </layoutData> 72 | </Input> 73 | <Input value="{ 74 | path : 'shipmentModel>/email', 75 | type : '.customEMailType' 76 | }" id="email" type="Email" valueStateText="E-Mail must be a valid email address."/> 77 | <Label text="Country/Region"/> 78 | <ComboBox id="country" items="{ 79 | path: 'countriesModel>/Countries', 80 | sorter: { path: 'name' } 81 | }"> 82 | <core:Item key="{countriesModel>key}" text="{countriesModel>name}" /> 83 | </ComboBox> 84 | <!-- <Button text="Create Order" press="onCreateOrder" type="Accept"></Button> --> 85 | </f:content> 86 | </f:SimpleForm> 87 | </VBox> 88 | </WizardStep> 89 | </Wizard> 90 | </NavContainer> 91 | <!-- <buttons> 92 | <Button text="Cancel" press="closeDialog"></Button> 93 | </buttons> --> 94 | </Dialog> 95 | 96 | </core:FragmentDefinition> 97 | -------------------------------------------------------------------------------- /approuter/xs-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "welcomeFile": "ui/index.html", 3 | "routes": [ 4 | { 5 | "source": "^/productService", 6 | "target": "/", 7 | "destination": "product-service", 8 | "scope": "$XSAPPNAME.Supplier" 9 | },{ 10 | "source": "^/logisticsService", 11 | "target": "/", 12 | "destination": "logisticsService", 13 | "scope": "$XSAPPNAME.Supplier" 14 | }, 15 | { 16 | "source": "^/ui/(.*)", 17 | "target" :"$1", 18 | "localDir": "ui/uimodule/webapp", 19 | "replace": { 20 | "pathSuffixes": [ 21 | "index.html" 22 | ] 23 | }, 24 | "scope": "$XSAPPNAME.Supplier" 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /db/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules -------------------------------------------------------------------------------- /db/manifest.yaml: -------------------------------------------------------------------------------- 1 | applications: 2 | - name: freight_db 3 | no-route: true 4 | type: hdb 5 | health-check-type: process 6 | memory: 128M 7 | services: 8 | - nodeapp_db 9 | -------------------------------------------------------------------------------- /db/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deploy", 3 | "lockfileVersion": 2, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "name": "deploy", 8 | "dependencies": { 9 | "@sap/hdi-deploy": "^4.8.2" 10 | } 11 | }, 12 | "node_modules/@sap/hdi-deploy": { 13 | "version": "4.8.2", 14 | "resolved": "https://registry.npmjs.org/@sap/hdi-deploy/-/hdi-deploy-4.8.2.tgz", 15 | "integrity": "sha512-LDouJ0i6oTLOrYWLeyp4PKF5cIBeKnn70gksdlg/bq3q5G/UNgGmqL62TEHbXehbeJfc0DKfEp9yal4IFD5k1Q==", 16 | "hasShrinkwrap": true, 17 | "dependencies": { 18 | "@sap/hana-client": "2.18.24", 19 | "@sap/hdi": "4.5.1", 20 | "@sap/xsenv": "3.4.0", 21 | "async": "3.2.3", 22 | "dotenv": "10.0.0", 23 | "handlebars": "4.7.7", 24 | "hdb": "0.19.3", 25 | "micromatch": "4.0.4" 26 | }, 27 | "engines": { 28 | "node": "^12.0.0 || ^14.0.0 || ^16.0.0 || ^18.0.0 || ^20.0.0" 29 | } 30 | }, 31 | "node_modules/@sap/hdi-deploy/node_modules/@sap/hana-client": { 32 | "version": "2.18.24", 33 | "dependencies": { 34 | "debug": "3.1.0" 35 | } 36 | }, 37 | "node_modules/@sap/hdi-deploy/node_modules/@sap/hana-client/node_modules/debug": { 38 | "version": "3.1.0", 39 | "dependencies": { 40 | "ms": "2.0.0" 41 | } 42 | }, 43 | "node_modules/@sap/hdi-deploy/node_modules/@sap/hana-client/node_modules/ms": { 44 | "version": "2.0.0" 45 | }, 46 | "node_modules/@sap/hdi-deploy/node_modules/@sap/hdi": { 47 | "version": "4.5.1", 48 | "dependencies": { 49 | "async": "3.2.3" 50 | } 51 | }, 52 | "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv": { 53 | "version": "3.4.0", 54 | "dependencies": { 55 | "debug": "4.3.3", 56 | "node-cache": "^5.1.0", 57 | "verror": "1.10.0" 58 | } 59 | }, 60 | "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/assert-plus": { 61 | "version": "1.0.0" 62 | }, 63 | "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/clone": { 64 | "version": "2.1.2" 65 | }, 66 | "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/core-util-is": { 67 | "version": "1.0.2" 68 | }, 69 | "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/debug": { 70 | "version": "4.3.3", 71 | "dependencies": { 72 | "ms": "2.1.2" 73 | } 74 | }, 75 | "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/extsprintf": { 76 | "version": "1.4.1" 77 | }, 78 | "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/ms": { 79 | "version": "2.1.2" 80 | }, 81 | "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/node-cache": { 82 | "version": "5.1.2", 83 | "dependencies": { 84 | "clone": "2.x" 85 | } 86 | }, 87 | "node_modules/@sap/hdi-deploy/node_modules/@sap/xsenv/node_modules/verror": { 88 | "version": "1.10.0", 89 | "dependencies": { 90 | "assert-plus": "^1.0.0", 91 | "core-util-is": "1.0.2", 92 | "extsprintf": "^1.2.0" 93 | } 94 | }, 95 | "node_modules/@sap/hdi-deploy/node_modules/async": { 96 | "version": "3.2.3" 97 | }, 98 | "node_modules/@sap/hdi-deploy/node_modules/braces": { 99 | "version": "3.0.2", 100 | "dependencies": { 101 | "fill-range": "^7.0.1" 102 | } 103 | }, 104 | "node_modules/@sap/hdi-deploy/node_modules/dotenv": { 105 | "version": "10.0.0" 106 | }, 107 | "node_modules/@sap/hdi-deploy/node_modules/fill-range": { 108 | "version": "7.0.1", 109 | "dependencies": { 110 | "to-regex-range": "^5.0.1" 111 | } 112 | }, 113 | "node_modules/@sap/hdi-deploy/node_modules/handlebars": { 114 | "version": "4.7.7", 115 | "dependencies": { 116 | "minimist": "^1.2.5", 117 | "neo-async": "^2.6.0", 118 | "source-map": "^0.6.1", 119 | "wordwrap": "^1.0.0" 120 | }, 121 | "optionalDependencies": { 122 | "uglify-js": "^3.1.4" 123 | } 124 | }, 125 | "node_modules/@sap/hdi-deploy/node_modules/hdb": { 126 | "version": "0.19.3", 127 | "dependencies": { 128 | "iconv-lite": "^0.4.18" 129 | } 130 | }, 131 | "node_modules/@sap/hdi-deploy/node_modules/iconv-lite": { 132 | "version": "0.4.24", 133 | "dependencies": { 134 | "safer-buffer": ">= 2.1.2 < 3" 135 | } 136 | }, 137 | "node_modules/@sap/hdi-deploy/node_modules/is-number": { 138 | "version": "7.0.0" 139 | }, 140 | "node_modules/@sap/hdi-deploy/node_modules/micromatch": { 141 | "version": "4.0.4", 142 | "dependencies": { 143 | "braces": "^3.0.1", 144 | "picomatch": "^2.2.3" 145 | } 146 | }, 147 | "node_modules/@sap/hdi-deploy/node_modules/minimist": { 148 | "version": "1.2.8" 149 | }, 150 | "node_modules/@sap/hdi-deploy/node_modules/neo-async": { 151 | "version": "2.6.2" 152 | }, 153 | "node_modules/@sap/hdi-deploy/node_modules/picomatch": { 154 | "version": "2.3.1" 155 | }, 156 | "node_modules/@sap/hdi-deploy/node_modules/safer-buffer": { 157 | "version": "2.1.2" 158 | }, 159 | "node_modules/@sap/hdi-deploy/node_modules/source-map": { 160 | "version": "0.6.1" 161 | }, 162 | "node_modules/@sap/hdi-deploy/node_modules/to-regex-range": { 163 | "version": "5.0.1", 164 | "dependencies": { 165 | "is-number": "^7.0.0" 166 | } 167 | }, 168 | "node_modules/@sap/hdi-deploy/node_modules/uglify-js": { 169 | "version": "3.17.4", 170 | "optional": true 171 | }, 172 | "node_modules/@sap/hdi-deploy/node_modules/wordwrap": { 173 | "version": "1.0.0" 174 | } 175 | }, 176 | "dependencies": { 177 | "@sap/hdi-deploy": { 178 | "version": "4.8.2", 179 | "resolved": "https://registry.npmjs.org/@sap/hdi-deploy/-/hdi-deploy-4.8.2.tgz", 180 | "integrity": "sha512-LDouJ0i6oTLOrYWLeyp4PKF5cIBeKnn70gksdlg/bq3q5G/UNgGmqL62TEHbXehbeJfc0DKfEp9yal4IFD5k1Q==", 181 | "requires": { 182 | "@sap/hana-client": "2.18.24", 183 | "@sap/hdi": "4.5.1", 184 | "@sap/xsenv": "3.4.0", 185 | "async": "3.2.3", 186 | "dotenv": "10.0.0", 187 | "handlebars": "4.7.7", 188 | "hdb": "0.19.3", 189 | "micromatch": "4.0.4" 190 | }, 191 | "dependencies": { 192 | "@sap/hana-client": { 193 | "version": "2.18.24", 194 | "requires": { 195 | "debug": "3.1.0" 196 | }, 197 | "dependencies": { 198 | "debug": { 199 | "version": "3.1.0", 200 | "requires": { 201 | "ms": "2.0.0" 202 | } 203 | }, 204 | "ms": { 205 | "version": "2.0.0" 206 | } 207 | } 208 | }, 209 | "@sap/hdi": { 210 | "version": "4.5.1", 211 | "requires": { 212 | "async": "3.2.3" 213 | } 214 | }, 215 | "@sap/xsenv": { 216 | "version": "3.4.0", 217 | "requires": { 218 | "debug": "4.3.3", 219 | "node-cache": "^5.1.0", 220 | "verror": "1.10.0" 221 | }, 222 | "dependencies": { 223 | "assert-plus": { 224 | "version": "1.0.0" 225 | }, 226 | "clone": { 227 | "version": "2.1.2" 228 | }, 229 | "core-util-is": { 230 | "version": "1.0.2" 231 | }, 232 | "debug": { 233 | "version": "4.3.3", 234 | "requires": { 235 | "ms": "2.1.2" 236 | } 237 | }, 238 | "extsprintf": { 239 | "version": "1.4.1" 240 | }, 241 | "ms": { 242 | "version": "2.1.2" 243 | }, 244 | "node-cache": { 245 | "version": "5.1.2", 246 | "requires": { 247 | "clone": "2.x" 248 | } 249 | }, 250 | "verror": { 251 | "version": "1.10.0", 252 | "requires": { 253 | "assert-plus": "^1.0.0", 254 | "core-util-is": "1.0.2", 255 | "extsprintf": "^1.2.0" 256 | } 257 | } 258 | } 259 | }, 260 | "async": { 261 | "version": "3.2.3" 262 | }, 263 | "braces": { 264 | "version": "3.0.2", 265 | "requires": { 266 | "fill-range": "^7.0.1" 267 | } 268 | }, 269 | "dotenv": { 270 | "version": "10.0.0" 271 | }, 272 | "fill-range": { 273 | "version": "7.0.1", 274 | "requires": { 275 | "to-regex-range": "^5.0.1" 276 | } 277 | }, 278 | "handlebars": { 279 | "version": "4.7.7", 280 | "requires": { 281 | "minimist": "^1.2.5", 282 | "neo-async": "^2.6.0", 283 | "source-map": "^0.6.1", 284 | "uglify-js": "^3.1.4", 285 | "wordwrap": "^1.0.0" 286 | } 287 | }, 288 | "hdb": { 289 | "version": "0.19.3", 290 | "requires": { 291 | "iconv-lite": "^0.4.18" 292 | } 293 | }, 294 | "iconv-lite": { 295 | "version": "0.4.24", 296 | "requires": { 297 | "safer-buffer": ">= 2.1.2 < 3" 298 | } 299 | }, 300 | "is-number": { 301 | "version": "7.0.0" 302 | }, 303 | "micromatch": { 304 | "version": "4.0.4", 305 | "requires": { 306 | "braces": "^3.0.1", 307 | "picomatch": "^2.2.3" 308 | } 309 | }, 310 | "minimist": { 311 | "version": "1.2.8" 312 | }, 313 | "neo-async": { 314 | "version": "2.6.2" 315 | }, 316 | "picomatch": { 317 | "version": "2.3.1" 318 | }, 319 | "safer-buffer": { 320 | "version": "2.1.2" 321 | }, 322 | "source-map": { 323 | "version": "0.6.1" 324 | }, 325 | "to-regex-range": { 326 | "version": "5.0.1", 327 | "requires": { 328 | "is-number": "^7.0.0" 329 | } 330 | }, 331 | "uglify-js": { 332 | "version": "3.17.4", 333 | "optional": true 334 | }, 335 | "wordwrap": { 336 | "version": "1.0.0" 337 | } 338 | } 339 | } 340 | } 341 | } 342 | -------------------------------------------------------------------------------- /db/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deploy", 3 | "dependencies": { 4 | "@sap/hdi-deploy": "^4.8.2" 5 | }, 6 | "scripts": { 7 | "start": "node node_modules/@sap/hdi-deploy/deploy.js" 8 | } 9 | } -------------------------------------------------------------------------------- /db/src/.hdiconfig: -------------------------------------------------------------------------------- 1 | { 2 | "file_suffixes": { 3 | "csv": { 4 | "plugin_name": "com.sap.hana.di.tabledata.source" 5 | }, 6 | "hdbafllangprocedure": { 7 | "plugin_name": "com.sap.hana.di.afllangprocedure" 8 | }, 9 | "hdbanalyticprivilege": { 10 | "plugin_name": "com.sap.hana.di.analyticprivilege" 11 | }, 12 | "hdbcalculationview": { 13 | "plugin_name": "com.sap.hana.di.calculationview" 14 | }, 15 | "hdbcds": { 16 | "plugin_name": "com.sap.hana.di.cds" 17 | }, 18 | "hdbcollection": { 19 | "plugin_name": "com.sap.hana.di.collection" 20 | }, 21 | "hdbconstraint": { 22 | "plugin_name": "com.sap.hana.di.constraint" 23 | }, 24 | "hdbdropcreatetable": { 25 | "plugin_name": "com.sap.hana.di.dropcreatetable" 26 | }, 27 | "hdbflowgraph": { 28 | "plugin_name": "com.sap.hana.di.flowgraph" 29 | }, 30 | "hdbfulltextindex": { 31 | "plugin_name": "com.sap.hana.di.fulltextindex" 32 | }, 33 | "hdbfunction": { 34 | "plugin_name": "com.sap.hana.di.function" 35 | }, 36 | "hdbgraphworkspace": { 37 | "plugin_name": "com.sap.hana.di.graphworkspace" 38 | }, 39 | "hdbhadoopmrjob": { 40 | "plugin_name": "com.sap.hana.di.virtualfunctionpackage.hadoop" 41 | }, 42 | "hdbindex": { 43 | "plugin_name": "com.sap.hana.di.index" 44 | }, 45 | "hdblibrary": { 46 | "plugin_name": "com.sap.hana.di.library" 47 | }, 48 | "hdbmigrationtable": { 49 | "plugin_name": "com.sap.hana.di.table.migration" 50 | }, 51 | "hdbprocedure": { 52 | "plugin_name": "com.sap.hana.di.procedure" 53 | }, 54 | "hdbprojectionview": { 55 | "plugin_name": "com.sap.hana.di.projectionview" 56 | }, 57 | "hdbprojectionviewconfig": { 58 | "plugin_name": "com.sap.hana.di.projectionview.config" 59 | }, 60 | "hdbreptask": { 61 | "plugin_name": "com.sap.hana.di.reptask" 62 | }, 63 | "hdbresultcache": { 64 | "plugin_name": "com.sap.hana.di.resultcache" 65 | }, 66 | "hdbrole": { 67 | "plugin_name": "com.sap.hana.di.role" 68 | }, 69 | "hdbroleconfig": { 70 | "plugin_name": "com.sap.hana.di.role.config" 71 | }, 72 | "hdbsearchruleset": { 73 | "plugin_name": "com.sap.hana.di.searchruleset" 74 | }, 75 | "hdbsequence": { 76 | "plugin_name": "com.sap.hana.di.sequence" 77 | }, 78 | "hdbstatistics": { 79 | "plugin_name": "com.sap.hana.di.statistics" 80 | }, 81 | "hdbstructuredprivilege": { 82 | "plugin_name": "com.sap.hana.di.structuredprivilege" 83 | }, 84 | "hdbsynonym": { 85 | "plugin_name": "com.sap.hana.di.synonym" 86 | }, 87 | "hdbsynonymconfig": { 88 | "plugin_name": "com.sap.hana.di.synonym.config" 89 | }, 90 | "hdbsystemversioning": { 91 | "plugin_name": "com.sap.hana.di.systemversioning" 92 | }, 93 | "hdbtable": { 94 | "plugin_name": "com.sap.hana.di.table" 95 | }, 96 | "hdbtabledata": { 97 | "plugin_name": "com.sap.hana.di.tabledata" 98 | }, 99 | "hdbtabletype": { 100 | "plugin_name": "com.sap.hana.di.tabletype" 101 | }, 102 | "hdbtextconfig": { 103 | "plugin_name": "com.sap.hana.di.textconfig" 104 | }, 105 | "hdbtextdict": { 106 | "plugin_name": "com.sap.hana.di.textdictionary" 107 | }, 108 | "hdbtextinclude": { 109 | "plugin_name": "com.sap.hana.di.textrule.include" 110 | }, 111 | "hdbtextlexicon": { 112 | "plugin_name": "com.sap.hana.di.textrule.lexicon" 113 | }, 114 | "hdbtextminingconfig": { 115 | "plugin_name": "com.sap.hana.di.textminingconfig" 116 | }, 117 | "hdbtextrule": { 118 | "plugin_name": "com.sap.hana.di.textrule" 119 | }, 120 | "hdbtrigger": { 121 | "plugin_name": "com.sap.hana.di.trigger" 122 | }, 123 | "hdbview": { 124 | "plugin_name": "com.sap.hana.di.view" 125 | }, 126 | "hdbvirtualfunction": { 127 | "plugin_name": "com.sap.hana.di.virtualfunction" 128 | }, 129 | "hdbvirtualfunctionconfig": { 130 | "plugin_name": "com.sap.hana.di.virtualfunction.config" 131 | }, 132 | "hdbvirtualpackagehadoop": { 133 | "plugin_name": "com.sap.hana.di.virtualpackage.hadoop" 134 | }, 135 | "hdbvirtualpackagesparksql": { 136 | "plugin_name": "com.sap.hana.di.virtualpackage.sparksql" 137 | }, 138 | "hdbvirtualprocedure": { 139 | "plugin_name": "com.sap.hana.di.virtualprocedure" 140 | }, 141 | "hdbvirtualprocedureconfig": { 142 | "plugin_name": "com.sap.hana.di.virtualprocedure.config" 143 | }, 144 | "hdbvirtualtable": { 145 | "plugin_name": "com.sap.hana.di.virtualtable" 146 | }, 147 | "hdbvirtualtableconfig": { 148 | "plugin_name": "com.sap.hana.di.virtualtable.config" 149 | }, 150 | "jar": { 151 | "plugin_name": "com.sap.hana.di.virtualfunctionpackage.hadoop" 152 | }, 153 | "properties": { 154 | "plugin_name": "com.sap.hana.di.tabledata.properties" 155 | }, 156 | "tags": { 157 | "plugin_name": "com.sap.hana.di.tabledata.properties" 158 | }, 159 | "txt": { 160 | "plugin_name": "com.sap.hana.di.copyonly" 161 | } 162 | } 163 | } -------------------------------------------------------------------------------- /db/src/.hdinamespace: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "subfolder": "ignore" 4 | } -------------------------------------------------------------------------------- /db/src/data/FreightOrder.hdbtable: -------------------------------------------------------------------------------- 1 | COLUMN TABLE "FreightOrder.freightOrder" ( 2 | ID VARCHAR(36), 3 | CREATED_BY VARCHAR(80), 4 | CREATED_AT VARCHAR(8), 5 | CONTACTPERSON VARCHAR(80), 6 | ADDRESS VARCHAR(100), 7 | PHONENUMBER VARCHAR(10), 8 | COUNTRYCODE VARCHAR(2), 9 | EMAIL VARCHAR(241), 10 | TOTALDISTANCEMEASURED Decimal(10,2), 11 | PRODUCTNAME VARCHAR(40), 12 | PRODUCTID VARCHAR(40), 13 | QUANTITY Integer, 14 | GROSSWEIGHT Decimal(13,2), 15 | TRANSPORTATIONMEANSTYPECODE VARCHAR(4), 16 | LIFECYCLESTATUSCODE VARCHAR(5), 17 | PICKUPDATE VARCHAR(8), 18 | DELIVERYDATE VARCHAR(8), 19 | TRANSPORTATIONCHARGES Decimal(23,2), 20 | CURRENCYCODE VARCHAR(3), 21 | PRIMARY KEY ("ID") ) -------------------------------------------------------------------------------- /db/src/data/Products.hdbtable: -------------------------------------------------------------------------------- 1 | COLUMN TABLE "Products.product" ( 2 | PRODUCTID VARCHAR(40) , 3 | PRODUCTNAME VARCHAR(40) , 4 | CURRENCYCODE VARCHAR(3) , 5 | CATEGORY VARCHAR(40) , 6 | WEIGHT Decimal(13,2) , 7 | WEIGHTUNIT VARCHAR(3) , 8 | SHORTDESCRIPTION VARCHAR(200) , 9 | PICTUREURL VARCHAR(255) , 10 | PRICE Decimal(23,3) , 11 | DIMENSIONWIDTH Decimal(13,4) , 12 | DIMENSIONDEPTH Decimal(13,4) , 13 | DIMENSIONHEIGHT Decimal(13,4) , 14 | DIMENSIONUNIT VARCHAR(3) , 15 | PRIMARY KEY ("PRODUCTID")); 16 | 17 | -------------------------------------------------------------------------------- /db/src/data/Products.hdbtabledata: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": 1, 3 | "imports": [ 4 | { 5 | "target_table": "Products.product", 6 | "source_data": { 7 | "data_type": "CSV", 8 | "file_name": "product.csv", 9 | "has_header": false, 10 | "type_config": { 11 | "delimiter": "," 12 | } 13 | }, 14 | "import_settings": { 15 | "import_columns": [ 16 | "PRODUCTID", 17 | "CURRENCYCODE", 18 | "CATEGORY", 19 | "WEIGHT", 20 | "WEIGHTUNIT", 21 | "SHORTDESCRIPTION", 22 | "PRODUCTNAME", 23 | "PICTUREURL", 24 | "PRICE", 25 | "DIMENSIONWIDTH", 26 | "DIMENSIONDEPTH", 27 | "DIMENSIONHEIGHT", 28 | "DIMENSIONUNIT" 29 | ] 30 | }, 31 | "column_mappings": { 32 | "PRODUCTID":1, 33 | "CURRENCYCODE":2, 34 | "CATEGORY":3, 35 | "WEIGHT":4, 36 | "WEIGHTUNIT":5, 37 | "SHORTDESCRIPTION":6, 38 | "PRODUCTNAME":7, 39 | "PICTUREURL":8, 40 | "PRICE":9, 41 | "DIMENSIONWIDTH":10, 42 | "DIMENSIONDEPTH":11, 43 | "DIMENSIONHEIGHT":12, 44 | "DIMENSIONUNIT":13 45 | } 46 | }, 47 | { 48 | "target_table": "Products.stock", 49 | "source_data": { 50 | "data_type": "CSV", 51 | "file_name": "stocks.csv", 52 | "has_header": false, 53 | "type_config": { 54 | "delimiter": "," 55 | } 56 | }, 57 | "import_settings": { 58 | "import_columns": [ 59 | "PRODUCTID", 60 | "QUANTITY" 61 | ] 62 | }, 63 | "column_mappings": { 64 | "PRODUCTID":1, 65 | "QUANTITY":2 66 | } 67 | } 68 | ] 69 | } -------------------------------------------------------------------------------- /db/src/data/Stock.hdbtable: -------------------------------------------------------------------------------- 1 | COLUMN TABLE "Products.stock" ( 2 | PRODUCTID VARCHAR(40) NOT NULL, 3 | QUANTITY INTEGER, 4 | PRIMARY KEY(PRODUCTID) 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /db/src/data/product.csv: -------------------------------------------------------------------------------- 1 | HT-1000,EUR,Notebooks,4.2,KG,"Notebook Basic 15 with 1,7GHz - 15"" XGA - 1024MB DDR2 SDRAM - 40GB Hard Disc",Notebook Basic 15,IMAGES/HT-1000.jpg,956,0.3,0.18,0.03,m 2 | HT-1001,EUR,Notebooks,4.5,KG,"Notebook Basic 17 with 1,7GHz - 17"" XGA - 1024MB DDR2 SDRAM - 40GB Hard Disc",Notebook Basic 17,IMAGES/HT-1001.jpg,1249,0.29,0.17,0.031,m 3 | HT-1002,EUR,Notebooks,4.2,KG,"Notebook Basic 18 with 1,7GHz - 18"" LCD - 1024MB DDR2 SDRAM - 40GB Hard Disc",Notebook Basic 18,IMAGES/HT-1002.jpg,1570,0.28,0.19,0.025,m 4 | HT-1003,EUR,Notebooks,4.2,KG,"Notebook Basic 19 with 1,7GHz - 19"" LCD - 1024MB DDR2 SDRAM - 40GB Hard Disc",Notebook Basic 19,IMAGES/HT-1003.jpg,1650,0.32,0.21,0.04,m 5 | HT-1010,EUR,Notebooks,4.3,KG,"Notebook Professional 15 with 2,3GHz - 15"" XGA - 2048MB DDR2 SDRAM - 40GB Hard Disc - DVD-Writer (DVD-R/+R/-RW/-RAM)",Notebook Professional 15,IMAGES/HT-1010.jpg,1999,0.33,0.2,0.03,m 6 | HT-1011,EUR,Notebooks,4.1,KG,"Notebook Professional 17 with 2,3GHz - 17"" XGA - 2048MB DDR2 SDRAM - 40GB Hard Disc - DVD-Writer (DVD-R/+R/-RW/-RAM)",Notebook Professional 17,IMAGES/HT-1011.jpg,2299,0.33,0.23,0.02,m 7 | HT-1030,EUR,Flat screens,18,KG,"17"" Optimum Resolution 1024 x 768 @ 85Hz, Max resolution 1280 x 960 @ 75Hz, Dot Pitch: 0.27mm",Ergo Screen,IMAGES/HT-1030.jpg,230,0.37,0.12,0.36,m 8 | HT-1031,EUR,Flat screens,22,KG,"19"" Optimum Resolution 1280 x 960 @ 85Hz, Max resolution 1600 x 1200 @ 75Hz, Dot Pitch: 0.26mm",Easy Pixel,IMAGES/HT-1031.jpg,285,0.408,0.19,0.43,m 9 | HT-1032,EUR,Flat screens,21,KG,"21"" Optimum Resolution 1600 x 1200 @ 85Hz, Max resolution 1984 x 1488 @ 75Hz, Dot Pitch: 0.25mm",Beam Screen,IMAGES/HT-1032.jpg,345,0.408,0.19,0.43,m 10 | HT-1035,EUR,Flat screens,14,KG,"19"" Optimum Resolution 1600 x 1200 @ 85Hz, Max resolution 1984 x 1488 @ 75Hz, Dot Pitch: 0.24mm",Flat Basic 15,IMAGES/HT-1035.jpg,399,0.39,0.2,0.41,m 11 | HT-1036,EUR,Flat screens,15,KG,"21"" Optimum Resolution 1984 x 1488 @ 85Hz, Max resolution 1720 x 1280 @ 75Hz, Dot Pitch: 0.24mm",Flat Future,IMAGES/HT-1036.jpg,430,0.45,0.26,0.46,m 12 | HT-1037,EUR,Flat screens,17,KG,"23"" Optimum Resolution 2016 x 1512 @ 85Hz, Max resolution 2048 x 1536 @ 75Hz, Dot Pitch: 0.24mm",Flat X-large,IMAGES/HT-1037.jpg,1430,0.545,0.221,0.391,m 13 | HT-1041,EUR,Laser printers,23,KG,"Up to 22 ppm color or 24 ppm monochrome letter, powerful 500 MHz processor and 128MB of memory",Laser Basic,IMAGES/HT-1041.jpg,490,0.48,0.42,0.26,m 14 | HT-1042,EUR,Laser printers,15,KG,"Print up to 25 ppm letter and 24 ppm A4 color or monochrome, with a first-page-out-time of less than 13 seconds for monochrome and less than 15 seconds for color",Laser Allround,IMAGES/HT-1042.jpg,349,0.53,0.5,0.65,m 15 | HT-1050,EUR,Ink jet printers,3,KG,"1200 dpi x 1200 dpi - up to 19 ppm (mono) / up to 18 ppm (colour) - capacity: 80 sheets - Hi-Speed USB, Ethernet",Deskjet Super Color,IMAGES/HT-1050.jpg,139,0.45,0.342,0.18,m 16 | HT-1051,EUR,Ink jet printers,1.9,KG,1000 dpi x 1000 dpi - up to 15 ppm (mono) / up to 13 ppm (colour) - capacity: 40 sheets - Hi-Speed USB - excellent dimesions for the small office,Deskjet Mobile,IMAGES/HT-1051.jpg,99,0.46,0.32,0.25,m 17 | HT-1052,EUR,Ink jet printers,18,KG,"1200 dpi x 1200 dpi - up to 25 ppm (mono) / up to 24 ppm (colour) - capacity: 100 sheets - Hi-Speed USB2.0, Ethernet",Deskjet Super Highspeed,IMAGES/HT-1052.jpg,170,0.41,0.42,0.28,m 18 | HT-1055,EUR,Multifunction printers,6.3,KG,"1000 dpi x 1000 dpi - up to 16 ppm (mono) / up to 15 ppm (colour)- capacity 80 sheets - scanner (216 x 297 mm, 1200dpi x 2400dpi)",Multi Print,IMAGES/HT-1055.jpg,99,0.55,0.45,0.29,m 19 | HT-1056,EUR,Multifunction printers,4.3,KG,"1200 dpi x 1200 dpi - up to 25 ppm (mono) / up to 24 ppm (colour)- capacity 80 sheets - scanner (216 x 297 mm, 2400dpi x 4800dpi, high resolution)",Multi Color,IMAGES/HT-1056.jpg,119,0.51,0.413,0.22,m 20 | HT-1063,EUR,Keyboards,2.1,KG,"Ergonomic USB PS/2 Keyboard for Desktop, Plug&Play",Ergonomic Keyboard,IMAGES/HT-1063.jpg,14,0.5,0.21,0.035,m 21 | HT-1064,EUR,Keyboards,1.8,KG,"Corded Keyboard with special keys for Internet Usability, USB",Internet Keyboard,IMAGES/HT-1064.jpg,16,0.52,0.25,0.03,m 22 | HT-1065,EUR,Keyboards,2.3,KG,"Corded Keyboard with special keys for Media Usability, USB",Media Keyboard,IMAGES/HT-1065.jpg,26,0.514,0.23,0.04,m 23 | HT-1069,EUR,Flat screens,170,G,"Replacement display for all 14'' IBM Thinkpad, Gercom Webboy. and HP Omnibook computers.",Notebook LCD Display,IMAGES/HT-1069.jpg,800,0.32,0.002,0.23,m 24 | HT-1080,EUR,Scanners,2.3,KG,Flatbed scanner - 1200 dpi x 1000 dpi - 216 x 297 mm - Hi-Speed USB - Bluetooth Ver. 1.2,Photo Scan,IMAGES/HT-1080.jpg,51,0.34,0.48,0.05,m 25 | HT-1081,EUR,Scanners,2.4,KG,Flatbed scanner - 1200 dpi x 1200 dpi - 216 x 297 mm - Hi-Speed USB - Bluetooth Ver. 1.2,Power Scan,IMAGES/HT-1081.jpg,89,0.31,0.43,0.07,m 26 | HT-1082,EUR,Scanners,3.2,KG,Flatbed scanner - Letter - 2400 dpi x 2400 dpi - 216 x 297 mm - Hi-Speed USB - Bluetooth Ver. 1.2,Jet Scan Professional,IMAGES/HT-1082.jpg,169,0.33,0.41,0.12,m 27 | HT-1083,EUR,Scanners,3.2,KG,Flatbed scanner - Letter - 2400 dpi x 2400 dpi - ADF ( 50 sheets ) - Hi-Speed USB - Bluetooth Ver. 1.2,Jet Scan Professional,IMAGES/HT-1083.jpg,520,0.35,0.4,0.1,m 28 | HT-1085,EUR,Multifunction printers,23.2,KG,Copymaster,Copymaster,IMAGES/HT-1085.jpg,1499,0.45,0.42,0.22,m 29 | HT-1090,EUR,Speakers,3,KG,PC multimedia speakers - 5 Watt (Total),Surround Sound,IMAGES/HT-1090.jpg,39,0.12,0.1,0.16,m 30 | HT-1091,EUR,Speakers,1.4,KG,PC multimedia speakers - 10 Watt (Total) - 2-way,Blaster Extreme,IMAGES/HT-1091.jpg,26,0.13,0.11,0.175,m 31 | HT-1092,EUR,Speakers,2.1,KG,PC multimedia speakers - 30 Watt (Total) - 2-way,Sound Booster,IMAGES/HT-1092.jpg,45,0.124,0.104,0.181,m 32 | HT-1120,EUR,Keyboards,1,KG,Corded Keyboard with english keys,"Keybord, english international",IMAGES/HT-1120.jpg,260,0.45,0.194,0.032,m 33 | HT-1138,EUR,Flat screens,4.2,KG,"23"" Optimum Resolution 2016 x 1512 @ 85Hz, Max resolution 2048 x 1536 @ 75Hz, Dot Pitch: 0.24mm",Flat XL,IMAGES/HT-1138.jpg,1211,0.53,0.2,0.44,m 34 | HT-1210,EUR,PCs,2.3,KG,"PC Power Station with 2,6 quad-core, 2 GB RAM, feels like a PC",PC Power Station,IMAGES/HT-1210.jpg,2399,0.28,0.31,0.43,m 35 | HT-1500,EUR,Servers,18,KG,"Dual socket, quad-core processing server with 1333 MHz Front Side Bus with 10Gb connectivity",Server Basic,IMAGES/HT-1500.jpg,5000,0.34,0.35,0.23,m 36 | HT-1501,EUR,Servers,25,KG,"Dual socket, quad-core processing server with 1644 MHz Front Side Bus with 10Gb connectivity",Server Professional,IMAGES/HT-1501.jpg,15000,0.29,0.3,0.27,m 37 | HT-1502,EUR,Servers,35,KG,"Dual socket, quad-core processing server with 1644 MHz Front Side Bus with 100Gb connectivity",Server Power Pro,IMAGES/HT-1502.jpg,25000,0.22,0.273,0.37,m 38 | HT-6130,EUR,TV flat screens,2.6,KG,"32 Zoll, 1366x768 Pixel, 16:9, HDTV ready",Flat Watch HD32,IMAGES/HT-6130.jpg,1459,0.78,0.221,0.55,m 39 | HT-6131,EUR,TV flat screens,2.2,KG,"37 Zoll, 1366x768 Pixel, 16:9, HDTV ready",Flat Watch HD37,IMAGES/HT-6131.jpg,1199,0.991,0.26,0.61,m 40 | HT-6132,EUR,TV flat screens,1.8,KG,"41 Zoll, 1366x768 Pixel, 16:9, HDTV ready",Flat Watch HD41,IMAGES/HT-6132.jpg,899,1.28,0.23,0.791,m 41 | HT-6102,EUR,Beamers,2.5,KG,"2500 ANSI-Lumen, max.12,3Meter, 800 Pixel, 600 Pixel",Beam Breaker B-3,,889,0.304,0.231,0.23,m 42 | HT-6101,EUR,Beamers,2,KG,"2200 ANSI-Lumen, max.9,34 Meter, 800 Pixel, 600 Pixel",Beam Breaker B-2,,679,0.32,0.21,0.18,m 43 | HT-6100,EUR,Beamers,1.7,KG,"1900 ANSI-Lumen, max. 8,45 Meter, 800 Pixel, 600 Pixel",Beam Breaker B-1,,469,0.18,0.15,0.12,m 44 | HT-1603,EUR,PCs,6.8,KG,"2,5 Ghz, quad core, 8 GB RAM, 700 GB Hdd, Graphic Card: Hurricane GX",Gaming Monster Pro,IMAGES/HT-1601.jpg,1700,0.27,0.28,0.42,m 45 | HT-1602,EUR,PCs,5.9,KG,"2,2 Ghz, dual core, 2 GB RAM, 400 GB Hdd, Graphic Card: Gladiator MX",Gaming Monster,IMAGES/HT-1602.jpg,1200,0.265,0.34,0.47,m 46 | HT-1601,EUR,PCs,5.3,KG,"2 Ghz, dual core, 1 GB RAM, 250 GB Hdd, Graphic Card: Gladiator MX",Family PC Pro,IMAGES/HT-1601.jpg,900,0.25,0.317,0.402,m 47 | HT-1600,EUR,PCs,4.8,KG,"1.8 Ghz, dual core,512 MB Ram, 100 GB HDD, Graphic Card: Proctra X",Family PC Basic,IMAGES/HT-1600.jpg,600,0.214,0.29,0.38,m 48 | HT-8000,EUR,Notebooks,4,KG,"1,5 Ghz, single core, 40 GB HDD, Windows Vista Home Basic, 512 MB RAM",ITelO FlexTop I4000,IMAGES/HT-8000.jpg,799,0.31,0.19,0.031,m 49 | HT-8001,EUR,Notebooks,4.2,KG,"1,6 Ghz, dual core, 60 GB HDD, Windows Vista Home Basic, 512 MB RAM+",ITelO FlexTop I6300c,IMAGES/HT-8001.jpg,999,0.32,0.2,0.034,m 50 | HT-8002,EUR,Notebooks,3.5,KG,"2,2 Ghz, quad core, 80 GB HDD, Windows Vista Home Premium, 1024 MB RAM",ITelO FlexTop I9100,IMAGES/HT-8002.jpg,1199,0.38,0.21,0.041,m 51 | HT-8003,EUR,Notebooks,3.8,KG,"2,8 Ghz, quad core, 120 GB HDD, Windows Vista Home Premium, 2048 MB RAM",ITelO FlexTop I9800,IMAGES/HT-8003.jpg,1388,0.48,0.31,0.045,m 52 | -------------------------------------------------------------------------------- /db/src/data/stocks.csv: -------------------------------------------------------------------------------- 1 | HT-1000,10000 2 | HT-1001,10 3 | HT-1002,10 4 | HT-1003,10 5 | HT-1010,10 6 | HT-1011,10 7 | HT-1030,10 8 | HT-1031,10 9 | HT-1032,10 10 | HT-1035,10 11 | HT-1036,10 12 | HT-1037,10 13 | HT-1041,10 14 | HT-1042,10 15 | HT-1050,10 16 | HT-1051,10 17 | HT-1052,10 18 | HT-1055,10 19 | HT-1056,10 20 | HT-1063,10 21 | HT-1064,10 22 | HT-1065,10 23 | HT-1069,10 24 | HT-1080,10 25 | HT-1081,10 26 | HT-1082,10 27 | HT-1083,10 28 | HT-1085,10 29 | HT-1090,10 30 | HT-1091,10 31 | HT-1092,10 32 | HT-1120,10 33 | HT-1138,10 34 | HT-1210,10 35 | HT-1500,10 36 | HT-1501,10 37 | HT-1502,10 38 | HT-6130,10 39 | HT-6131,10 40 | HT-6132,10 41 | HT-6102,10 42 | HT-6101,10 43 | HT-6100,10 44 | HT-1603,10 45 | HT-1602,10 46 | HT-1601,10 47 | HT-1600,10 48 | HT-8000,10 49 | HT-8001,10 50 | HT-8002,10 51 | HT-8003,10 -------------------------------------------------------------------------------- /freight-manager/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | sourceType: 'module', 6 | }, 7 | plugins: ['@typescript-eslint/eslint-plugin'], 8 | extends: [ 9 | 'plugin:@typescript-eslint/eslint-recommended', 10 | 'plugin:@typescript-eslint/recommended', 11 | 'prettier', 12 | 'prettier/@typescript-eslint', 13 | ], 14 | root: true, 15 | env: { 16 | node: true, 17 | jest: true, 18 | }, 19 | rules: { 20 | '@typescript-eslint/interface-name-prefix': 'off', 21 | '@typescript-eslint/explicit-function-return-type': 'off', 22 | '@typescript-eslint/no-explicit-any': 'off', 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /freight-manager/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # OS 14 | .DS_Store 15 | 16 | # Tests 17 | /coverage 18 | /.nyc_output 19 | 20 | # IDEs and editors 21 | /.idea 22 | .project 23 | .classpath 24 | .c9/ 25 | *.launch 26 | .settings/ 27 | *.sublime-workspace 28 | 29 | # IDE - VSCode 30 | .vscode/* 31 | !.vscode/settings.json 32 | !.vscode/tasks.json 33 | !.vscode/launch.json 34 | !.vscode/extensions.json 35 | credentials.json 36 | /s4hana_pipeline 37 | /deployment 38 | -------------------------------------------------------------------------------- /freight-manager/.npmrc: -------------------------------------------------------------------------------- 1 | @sap:registry=https://registry.npmjs.org -------------------------------------------------------------------------------- /freight-manager/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /freight-manager/manifest.yml: -------------------------------------------------------------------------------- 1 | applications: 2 | - name: freight-manager 3 | path: deployment/ 4 | buildpacks: 5 | - nodejs_buildpack 6 | memory: 256M 7 | command: npm run start:prod 8 | random-route: true 9 | services: 10 | - freight-xsuaa 11 | -------------------------------------------------------------------------------- /freight-manager/nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "@nestjs/schematics", 3 | "sourceRoot": "src" 4 | } 5 | -------------------------------------------------------------------------------- /freight-manager/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "freight-manager", 3 | "version": "0.0.1", 4 | "description": "", 5 | "author": "", 6 | "private": true, 7 | "license": "UNLICENSED", 8 | "scripts": { 9 | "prebuild": "rimraf dist", 10 | "build": "nest build", 11 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", 12 | "start": "nest start", 13 | "start:dev": "nest start --watch", 14 | "start:debug": "nest start --debug --watch", 15 | "start:prod": "node dist/main", 16 | "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", 17 | "test": "jest", 18 | "test:watch": "jest --watch", 19 | "test:cov": "jest --coverage", 20 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", 21 | "test:e2e": "jest --config ./test/jest-e2e.json", 22 | "deploy": "npm run build && sap-cloud-sdk package && cf push", 23 | "ci-build": "npm run build", 24 | "ci-package": "sap-cloud-sdk package", 25 | "ci-integration-test": "jest --ci --config ./test/jest-e2e.json", 26 | "ci-backend-unit-test": "jest --ci" 27 | }, 28 | "dependencies": { 29 | "@nestjs/common": "^9.1.4", 30 | "@nestjs/core": "^9.1.4", 31 | "@nestjs/platform-express": "^9.1.4", 32 | "@nestjs/swagger": "^6.1.2", 33 | "@sap/xsenv": "^4.2.0", 34 | "@sap/xssec": "^3.6.0", 35 | "passport": "^0.6.0", 36 | "reflect-metadata": "^0.1.13", 37 | "rimraf": "^3.0.2", 38 | "rxjs": "^7.3.1" 39 | }, 40 | "devDependencies": { 41 | "@nestjs/cli": "^9.1.4", 42 | "@nestjs/schematics": "^9.0.3", 43 | "@nestjs/testing": "^9.1.4", 44 | "@types/express": "^4.17.13", 45 | "@types/jest": "27.0.2", 46 | "@types/node": "^18.15.11", 47 | "@types/supertest": "^2.0.11", 48 | "@typescript-eslint/eslint-plugin": "3.0.2", 49 | "@typescript-eslint/parser": "3.0.2", 50 | "eslint": "^7.32.0", 51 | "eslint-config-prettier": "^8.3.0", 52 | "eslint-plugin-import": "^2.20.1", 53 | "jest-junit": "^13.0.0", 54 | "prettier": "^1.19.1", 55 | "supertest": "^4.0.2", 56 | "swagger-ui-express": "^4.3.0", 57 | "ts-jest": "27.0.5", 58 | "ts-loader": "^9.2.6", 59 | "ts-node": "^10.2.1", 60 | "tsconfig-paths": "^3.11.0", 61 | "typescript": "^4.3.5" 62 | }, 63 | "jest": { 64 | "moduleFileExtensions": [ 65 | "js", 66 | "json", 67 | "ts" 68 | ], 69 | "rootDir": "src", 70 | "testRegex": ".spec.ts$", 71 | "transform": { 72 | "^.+\\.(t|j)s$": "ts-jest" 73 | }, 74 | "coverageDirectory": "../s4hana_pipeline/reports/coverage-reports/backend-unit", 75 | "testEnvironment": "node", 76 | "reporters": [ 77 | "default", 78 | [ 79 | "jest-junit", 80 | { 81 | "suiteName": "backend unit tests", 82 | "outputDirectory": "./s4hana_pipeline/reports/backend-unit" 83 | } 84 | ] 85 | ], 86 | "collectCoverage": true, 87 | "coverageReporters": [ 88 | "text", 89 | "cobertura" 90 | ] 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /freight-manager/sap-cloud-sdk-analytics.json: -------------------------------------------------------------------------------- 1 | {"enabled":false} -------------------------------------------------------------------------------- /freight-manager/src/freight-service/freight.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AppController } from './freight.controller'; 3 | import { AppService } from './freight.service'; 4 | 5 | describe('AppController', () => { 6 | let appController: AppController; 7 | 8 | beforeEach(async () => { 9 | const app: TestingModule = await Test.createTestingModule({ 10 | controllers: [AppController], 11 | providers: [AppService], 12 | }).compile(); 13 | 14 | appController = app.get<AppController>(AppController); 15 | }); 16 | 17 | describe('root', () => { 18 | // it('should return "Hello World!"', () => { 19 | // expect(appController.getHello()).toBe('Hello World!'); 20 | // }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /freight-manager/src/freight-service/freight.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Query, ParseIntPipe, Req, UnauthorizedException } from '@nestjs/common'; 2 | import { AppService } from './freight.service'; 3 | import { ApiBearerAuth, ApiTags, ApiQuery } from '@nestjs/swagger'; 4 | @Controller() 5 | export class AppController { 6 | constructor(private readonly appService: AppService) { } 7 | /** 8 | * Swagger defination starts here 9 | */ 10 | @Get() 11 | @ApiBearerAuth() 12 | @ApiTags('Freight Service') 13 | @ApiQuery({ 14 | name: 'transportationmeans', 15 | description: 'Mode of transportation (AIR, ROAD, SHIP, RAIL)', 16 | type: String 17 | }) 18 | @ApiQuery({ 19 | name: 'quantity', 20 | description: 'Number of items to be shipped', 21 | type: Number 22 | }) 23 | @ApiQuery({ 24 | name: 'totalDistanceMeasured', 25 | description: 'Distance for delivery', 26 | type: String 27 | }) 28 | @ApiQuery({ 29 | name: 'weight', 30 | description: 'Product Weight', 31 | type: String 32 | }) 33 | @ApiQuery({ 34 | name: 'dimension', 35 | description: 'Product dimension(Height,length,width)', 36 | type: String 37 | }) 38 | // end of swagger defination 39 | 40 | /** 41 | * Gets query parameters required for calucation for freight order 42 | */ 43 | getQuote(@Req() req: any,@Query('transportationmeans') transportationMeans: string, @Query('weight', ParseIntPipe) weight: number, 44 | @Query('dimension') dimension: string, @Query('totalDistanceMeasured', ParseIntPipe) totalDistanceMeasured: number, 45 | @Query('quantity', ParseIntPipe) quantity: number): number { 46 | 47 | const isAuthorized = req.authInfo.checkLocalScope('Access'); 48 | if(isAuthorized){ 49 | let transportationCharges = this.appService.getQuote(transportationMeans, weight, dimension, totalDistanceMeasured, quantity); 50 | return transportationCharges; 51 | }else{ 52 | throw new UnauthorizedException(); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /freight-manager/src/freight-service/freight.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { AppController } from './freight.controller'; 3 | import { AppService } from './freight.service'; 4 | 5 | @Module({ 6 | imports: [], 7 | controllers: [AppController], 8 | providers: [AppService], 9 | }) 10 | export class AppModule {} 11 | -------------------------------------------------------------------------------- /freight-manager/src/freight-service/freight.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpException, Injectable } from '@nestjs/common'; 2 | const quote = { "RAIL": 1000, "ROAD": 2000, "SHIP": 3000, "AIR": 4000 } 3 | const standardShippingCost = 3; 4 | const distanceCostPerKM = 0.1; 5 | const weightPerKG = 2; 6 | @Injectable() 7 | export class AppService { 8 | getQuote(transportationMeans: string, weight: number, dimension: string, totalDistanceMeasured: number, quantity: number): number { 9 | if(dimension.split(",").length === 3){ 10 | let dim = dimension.split(','); 11 | let dimestionFactor = 166; 12 | let dimensionWeight = Math.ceil(((parseFloat(dim[0]) * parseFloat(dim[1]) * parseFloat(dim[2])) * 39.37) / dimestionFactor); // convert meter into inches. 1 m = 39.37 inch 13 | // formula : if pick the greatest among dimenstionWeight and weight and multiply it with cost per weight in kg(ensure the weight is in celi format) 14 | let calculationWeight = dimensionWeight > Math.ceil(weight) ? dimensionWeight : Math.ceil(weight); 15 | let distanceCost = totalDistanceMeasured > 400 ? 0 : (totalDistanceMeasured - 400) * distanceCostPerKM; 16 | let transportationCharges = calculationWeight * weightPerKG + distanceCost + standardShippingCost + quote[transportationMeans] * quantity; 17 | return transportationCharges; 18 | }else{ 19 | throw new HttpException('Invalid Dimension', 400); 20 | } 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /freight-manager/src/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import { AppModule } from './freight-service/freight.module'; 3 | import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; 4 | 5 | import { getServices } from '@sap/xsenv'; 6 | const xsuaa = getServices({ xsuaa: { tag: 'xsuaa' } }).xsuaa; 7 | import * as passport from 'passport'; 8 | import { JWTStrategy } from '@sap/xssec'; 9 | passport.use(new JWTStrategy(xsuaa)); 10 | 11 | async function bootstrap() { 12 | const app = await NestFactory.create(AppModule); 13 | 14 | //swagger Initialization 15 | const options = new DocumentBuilder() 16 | .setTitle('Freight Manager') 17 | .setDescription('APIs for Freight Manager') 18 | .setVersion('1.0').addBearerAuth() 19 | .build(); 20 | const document = SwaggerModule.createDocument(app, options); 21 | SwaggerModule.setup('api', app, document); 22 | //security implementation 23 | app.use(passport.initialize()); 24 | app.use(passport.authenticate('JWT', { session: false })); 25 | await app.listen(process.env.PORT || 3000); 26 | } 27 | bootstrap(); 28 | -------------------------------------------------------------------------------- /freight-manager/systems.json: -------------------------------------------------------------------------------- 1 | { 2 | "systems": [{ 3 | "alias": "EXAMPLE", 4 | "uri": "https://example.com" 5 | }] 6 | } 7 | -------------------------------------------------------------------------------- /freight-manager/test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { INestApplication } from '@nestjs/common'; 3 | import * as request from 'supertest'; 4 | import { AppModule } from '../src/freight-service/freight.module'; 5 | 6 | describe('AppController (e2e)', () => { 7 | let app: INestApplication; 8 | 9 | beforeEach(async () => { 10 | const moduleFixture: TestingModule = await Test.createTestingModule({ 11 | imports: [AppModule], 12 | }).compile(); 13 | 14 | app = moduleFixture.createNestApplication(); 15 | await app.init(); 16 | }); 17 | 18 | it('/ (GET)', () => { 19 | return request(app.getHttpServer()) 20 | .get('/') 21 | .expect(200) 22 | .expect('Hello World!'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /freight-manager/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": [ 3 | "js", 4 | "json", 5 | "ts" 6 | ], 7 | "rootDir": ".", 8 | "testEnvironment": "node", 9 | "testRegex": ".e2e-spec.ts$", 10 | "transform": { 11 | "^.+\\.(t|j)s$": "ts-jest" 12 | }, 13 | "reporters": [ 14 | "default", 15 | [ 16 | "jest-junit", 17 | { 18 | "suiteName": "backend unit tests", 19 | "outputDirectory": "./s4hana_pipeline/reports/backend-integration" 20 | } 21 | ] 22 | ], 23 | "collectCoverage": true, 24 | "coverageReporters": [ 25 | "text", 26 | "cobertura" 27 | ], 28 | "coverageDirectory": "../s4hana_pipeline/reports/coverage-reports/backend-integration" 29 | } -------------------------------------------------------------------------------- /freight-manager/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /freight-manager/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "es2017", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /freight-manager/xs-security.json: -------------------------------------------------------------------------------- 1 | { 2 | "xsappname": "freight-xsuaa", 3 | "tenant-mode": "dedicated", 4 | "scopes": [ 5 | { 6 | "name": "$XSAPPNAME.Access", 7 | "description": "access freight service ", 8 | "grant-as-authority-to-apps": ["$XSAPPNAME(application,businessuser-authentication)"] 9 | } 10 | ], 11 | "role-templates": [ 12 | { 13 | "name": "freightservice", 14 | "description": "access freight service ", 15 | "scope-references": [ 16 | "$XSAPPNAME.Access" 17 | ] 18 | } 19 | ], 20 | "oauth2-configuration": { 21 | "redirect-uris": [ 22 | "https://*.cfapps.eu10-004.hana.ondemand.com/**", 23 | "https://*.cfapps.eu10.hana.ondemand.com/**" 24 | ] 25 | } 26 | } -------------------------------------------------------------------------------- /images/address-details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/address-details.png -------------------------------------------------------------------------------- /images/bullet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/bullet.png -------------------------------------------------------------------------------- /images/create-order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/create-order.png -------------------------------------------------------------------------------- /images/dbid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/dbid.png -------------------------------------------------------------------------------- /images/destination.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/destination.png -------------------------------------------------------------------------------- /images/env-logistics-service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/env-logistics-service.png -------------------------------------------------------------------------------- /images/hana-cockpit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/hana-cockpit.png -------------------------------------------------------------------------------- /images/hana.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/hana.PNG -------------------------------------------------------------------------------- /images/hr.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/hr.gif -------------------------------------------------------------------------------- /images/login page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/login page.png -------------------------------------------------------------------------------- /images/nav-bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/nav-bg.gif -------------------------------------------------------------------------------- /images/postman-token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/postman-token.png -------------------------------------------------------------------------------- /images/request-quote.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/request-quote.png -------------------------------------------------------------------------------- /images/select-product.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/select-product.png -------------------------------------------------------------------------------- /images/selected-product.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/selected-product.png -------------------------------------------------------------------------------- /images/shipment orders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/shipment orders.png -------------------------------------------------------------------------------- /images/solutiondiagram.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/solutiondiagram.PNG -------------------------------------------------------------------------------- /images/solutiondiagram_updated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/solutiondiagram_updated.png -------------------------------------------------------------------------------- /images/swagger-execute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/swagger-execute.png -------------------------------------------------------------------------------- /images/swagger-post.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/swagger-post.png -------------------------------------------------------------------------------- /images/swagger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/swagger.png -------------------------------------------------------------------------------- /images/tam.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SAP-samples/cloud-nodejs-oflm/e3895789cae7a9883edbaf9689e4240f745095e4/images/tam.PNG -------------------------------------------------------------------------------- /logistics-service/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | sourceType: 'module', 6 | }, 7 | plugins: ['@typescript-eslint/eslint-plugin'], 8 | extends: [ 9 | 'plugin:@typescript-eslint/eslint-recommended', 10 | 'plugin:@typescript-eslint/recommended', 11 | 'prettier', 12 | 'prettier/@typescript-eslint', 13 | ], 14 | root: true, 15 | env: { 16 | node: true, 17 | jest: true, 18 | }, 19 | rules: { 20 | '@typescript-eslint/interface-name-prefix': 'off', 21 | '@typescript-eslint/explicit-function-return-type': 'off', 22 | '@typescript-eslint/no-explicit-any': 'off', 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /logistics-service/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # OS 14 | .DS_Store 15 | 16 | # Tests 17 | /coverage 18 | /.nyc_output 19 | 20 | # IDEs and editors 21 | /.idea 22 | .project 23 | .classpath 24 | .c9/ 25 | *.launch 26 | .settings/ 27 | *.sublime-workspace 28 | 29 | # IDE - VSCode 30 | .vscode/* 31 | !.vscode/settings.json 32 | !.vscode/tasks.json 33 | !.vscode/launch.json 34 | !.vscode/extensions.json 35 | credentials.json 36 | /s4hana_pipeline 37 | /deployment 38 | -------------------------------------------------------------------------------- /logistics-service/.npmrc: -------------------------------------------------------------------------------- 1 | @sap:registry=https://registry.npmjs.org 2 | -------------------------------------------------------------------------------- /logistics-service/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /logistics-service/manifest.yml: -------------------------------------------------------------------------------- 1 | applications: 2 | - name: logistics-service 3 | path: deployment/ 4 | buildpacks: 5 | - nodejs_buildpack 6 | memory: 256M 7 | command: npm run start:prod 8 | random-route: true 9 | services: 10 | - businessuser-authentication 11 | - nodeapp_db 12 | - freight-manager 13 | env: 14 | product_service: https://product-service-zany-wallaby-ns.cfapps.eu10-004.hana.ondemand.com 15 | -------------------------------------------------------------------------------- /logistics-service/nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "@nestjs/schematics", 3 | "sourceRoot": "src" 4 | } 5 | -------------------------------------------------------------------------------- /logistics-service/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "", 3 | "dependencies": { 4 | "@nestjs/axios": "^0.1.0", 5 | "@nestjs/common": "^9.1.4", 6 | "@nestjs/core": "^9.1.4", 7 | "@nestjs/platform-express": "^9.1.4", 8 | "@nestjs/swagger": "^6.1.2", 9 | "@sap-cloud-sdk/connectivity": "^3.9.0", 10 | "@sap/hdbext": "^8.0.2", 11 | "@sap/xsenv": "^4.2.0", 12 | "@sap/xssec": "^3.6.0", 13 | "axios": "^0.22.0", 14 | "class-validator": "^0.14.0", 15 | "passport": "^0.6.0", 16 | "reflect-metadata": "^0.1.13", 17 | "rimraf": "^3.0.2", 18 | "rxjs": "^7.3.0", 19 | "swagger-ui-express": "^4.0.2", 20 | "uuid": "^8.3.2" 21 | }, 22 | "description": "", 23 | "devDependencies": { 24 | "@nestjs/cli": "^9.1.4", 25 | "@nestjs/schematics": "^9.0.3", 26 | "@nestjs/testing": "^9.1.4", 27 | "@types/express": "^4.17.13", 28 | "@types/jest": "27.0.1", 29 | "@types/node": "^18.15.11", 30 | "@types/supertest": "^2.0.11", 31 | "@typescript-eslint/eslint-plugin": "3.0.2", 32 | "@typescript-eslint/parser": "3.0.2", 33 | "eslint": "^7.32.0", 34 | "eslint-config-prettier": "^6.10.0", 35 | "eslint-plugin-import": "^2.20.1", 36 | "jest": "27.1.0", 37 | "jest-junit": "^13.0.0", 38 | "prettier": "^2.3.2", 39 | "supertest": "^6.1.6", 40 | "ts-jest": "27.0.5", 41 | "ts-loader": "^9.2.5", 42 | "ts-node": "^10.2.0", 43 | "tsconfig-paths": "^3.10.1", 44 | "typescript": "^4.3.5" 45 | }, 46 | "jest": { 47 | "collectCoverage": true, 48 | "coverageDirectory": "../s4hana_pipeline/reports/coverage-reports/backend-unit", 49 | "coverageReporters": [ 50 | "text", 51 | "cobertura" 52 | ], 53 | "moduleFileExtensions": [ 54 | "js", 55 | "json", 56 | "ts" 57 | ], 58 | "reporters": [ 59 | "default", 60 | [ 61 | "jest-junit", 62 | { 63 | "outputDirectory": "./s4hana_pipeline/reports/backend-unit", 64 | "suiteName": "backend unit tests" 65 | } 66 | ] 67 | ], 68 | "rootDir": "src", 69 | "testEnvironment": "node", 70 | "testRegex": ".spec.ts$", 71 | "transform": { 72 | "^.+\\.(t|j)s$": "ts-jest" 73 | } 74 | }, 75 | "license": "UNLICENSED", 76 | "name": "logistics-service", 77 | "private": true, 78 | "scripts": { 79 | "build": "nest build", 80 | "ci-backend-unit-test": "jest --ci", 81 | "ci-build": "npm run build", 82 | "ci-integration-test": "jest --ci --config ./test/jest-e2e.json", 83 | "ci-package": "sap-cloud-sdk package --ci", 84 | "deploy": "npm run build && sap-cloud-sdk package && cf push", 85 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", 86 | "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", 87 | "prebuild": "rimraf dist", 88 | "start": "nest start", 89 | "start:debug": "nest start --debug --watch", 90 | "start:dev": "nest start --watch", 91 | "start:prod": "node dist/main", 92 | "test": "jest", 93 | "test:cov": "jest --coverage", 94 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", 95 | "test:e2e": "jest --config ./test/jest-e2e.json", 96 | "test:watch": "jest --watch" 97 | }, 98 | "version": "0.0.1" 99 | } 100 | -------------------------------------------------------------------------------- /logistics-service/sap-cloud-sdk-analytics.json: -------------------------------------------------------------------------------- 1 | { 2 | "enabled": true, 3 | "salt": "8ff41abb176a3749269a145728eba7b7c87c7cce82c2a02c6d6e61f653d495d3" 4 | } -------------------------------------------------------------------------------- /logistics-service/src/app.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | 5 | describe('AppController', () => { 6 | let appController: AppController; 7 | 8 | beforeEach(async () => { 9 | const app: TestingModule = await Test.createTestingModule({ 10 | controllers: [AppController], 11 | providers: [AppService], 12 | }).compile(); 13 | 14 | appController = app.get<AppController>(AppController); 15 | }); 16 | 17 | describe('root', () => { 18 | it('should return "Hello World!"', () => { 19 | expect(appController.getHello()).toBe('Hello World!'); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /logistics-service/src/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '@nestjs/common'; 2 | import { AppService } from './app.service'; 3 | 4 | @Controller() 5 | export class AppController { 6 | constructor(private readonly appService: AppService) {} 7 | 8 | @Get() 9 | getHello(): string { 10 | return this.appService.getHello(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /logistics-service/src/app.module.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Module } from '@nestjs/common'; 3 | import { HttpModule } from '@nestjs/axios'; 4 | import { AppController } from './app.controller'; 5 | import { AppService } from './app.service'; 6 | import { QuoteModule } from './logistics/quote.module'; 7 | import { QuoteService } from './logistics/quote.service'; 8 | import {OrderModule} from './logistics/order.module'; 9 | import {OrderService} from './logistics/order.service'; 10 | @Module({ 11 | imports: [ 12 | QuoteModule, HttpModule, OrderModule], 13 | controllers: [AppController], 14 | providers: [ 15 | QuoteService, AppService, OrderService], 16 | }) 17 | export class AppModule { } 18 | -------------------------------------------------------------------------------- /logistics-service/src/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AppService { 5 | getHello(): string { 6 | return 'Hello SAP!'; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /logistics-service/src/logistics/order.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Post, Body, Get, Req, ForbiddenException } from '@nestjs/common'; 2 | import { OrderService } from './order.service'; 3 | import { ApiBearerAuth, ApiOperation, ApiTags} from '@nestjs/swagger'; 4 | import { FreightOrder } from '../model/quotemodel.dto'; 5 | @Controller('order') 6 | export class OrderController { 7 | constructor(private readonly orderService: OrderService) { } 8 | @Post() 9 | /** 10 | * API annotations are used for swagger implementation 11 | * API Tags help the endpoints in their grouping 12 | */ 13 | @ApiBearerAuth() 14 | @ApiTags('Logistics Service') 15 | @ApiOperation({ summary: 'Create freight order' }) 16 | /** 17 | * To create a new freight order 18 | * @Req {object} gets the request details 19 | * @Body is having Implementation of freightOrder class which specifies what are all the required payloads 20 | */ 21 | async createFreightOrder(@Req() req: any, @Body() freightOder: FreightOrder) { 22 | const isAuthorized = req.authInfo.checkLocalScope('Supplier'); 23 | if (isAuthorized) { 24 | const hanaClient = req.db; 25 | return await this.orderService.createFreightOrder(freightOder,req.user.id, hanaClient).then(result=>{ 26 | return result; 27 | }).catch(err=>{ 28 | throw err; 29 | }); 30 | } else { 31 | throw new ForbiddenException(); 32 | } 33 | } 34 | 35 | /** 36 | * 37 | * @param req gets request object containing authorization information 38 | * this method returns in getting all the freight orders created 39 | */ 40 | @Get() 41 | @ApiBearerAuth() 42 | @ApiTags('Logistics Service') 43 | @ApiOperation({ summary: 'Get all Order' }) 44 | async getFreightOrder(@Req() req: any) { 45 | const isAuthorized = req.authInfo.checkLocalScope('Supplier'); 46 | if (isAuthorized) { 47 | const hanaClient = req.db; 48 | return await this.orderService.getOrders(hanaClient); 49 | } else { 50 | throw new ForbiddenException(); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /logistics-service/src/logistics/order.module.ts: -------------------------------------------------------------------------------- 1 | import { OrderController } from './order.controller'; 2 | import { OrderService } from './order.service'; 3 | import { Module } from '@nestjs/common'; 4 | 5 | @Module({ 6 | imports: [], 7 | controllers: [ 8 | OrderController], 9 | providers: [ 10 | OrderService], 11 | }) 12 | export class OrderModule { } 13 | -------------------------------------------------------------------------------- /logistics-service/src/logistics/order.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { v4 as uuidv4 } from 'uuid'; 3 | @Injectable() 4 | export class OrderService { 5 | async createFreightOrder(data: any, user:string, hanaClient : any): Promise<any> { 6 | const query = `INSERT INTO "FreightOrder.freightOrder" VALUES('${uuidv4()}','${user}', 7 | '${data.pickupdate}','${data.contactPerson}','${data.address}','${data.phone}','${data.countryCode}','${data.email}', 8 | '${data.totalDistanceMeasured}','${data.productName}', 9 | '${data.productId}','${data.quantity}','${data.grossWeight}','${data.transportationMeansType}','${data.lifecyclestatus}', 10 | '${data.pickupdate}','${data.deliverydate}','${data.transportationCharges}','${data.currencycode}')`; 11 | return await this.query(query,hanaClient).then(res => { 12 | return "Order Created"; 13 | }).catch(err => { 14 | console.log(err); 15 | throw err; 16 | }); 17 | } 18 | async getOrders(hanaClient: any): Promise<any> { 19 | const query = `SELECT * FROM "FreightOrder.freightOrder"`; 20 | return await this.query(query,hanaClient).then(res => { 21 | return res; 22 | }).catch(err => { 23 | throw err; 24 | }); 25 | } 26 | /** 27 | * 28 | * @param query String HANA Query 29 | * returns the query execution result 30 | */ 31 | async query(query: string, hanaClient: any) { 32 | return new Promise((resolve, reject) => { 33 | hanaClient.exec(query, (err: unknown, result: Object) => { 34 | if (err) reject(err); 35 | resolve(result); 36 | }); 37 | }) 38 | } 39 | } -------------------------------------------------------------------------------- /logistics-service/src/logistics/quote.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Query, Catch, HttpException, HttpStatus, Req, UnauthorizedException, ParseIntPipe } from '@nestjs/common'; 2 | import { QuoteService } from './quote.service'; 3 | import { ApiBearerAuth, ApiOperation, ApiTags, ApiQuery, ApiResponse } from '@nestjs/swagger'; 4 | @Controller('getQuote') 5 | @Catch() 6 | export class QuoteController { 7 | constructor(private readonly quoteService: QuoteService) { } 8 | /** 9 | * 10 | * @param req authorization header 11 | * @param mode mode of transport 12 | * @param productId 13 | * @param quantity 14 | * @param totalDistanceMeasured 15 | * @param weight 16 | * @param dimension 17 | * @Get annotation is used for swagger implementation 18 | */ 19 | 20 | /** 21 | * Swagger defination goes here 22 | */ 23 | @Get() 24 | @ApiBearerAuth() 25 | @ApiTags('Logistics Service') 26 | @ApiOperation({ summary: 'Get Quote from freight service using technical user authentication' }) 27 | @ApiQuery({ 28 | name: 'mode', 29 | description: 'Mode of transportation (Air, Water, Rail, Road)', 30 | type: String 31 | }) 32 | @ApiQuery({ 33 | name: 'quantity', 34 | description: 'Number of items to be shipped', 35 | type: Number 36 | }) 37 | @ApiQuery({ 38 | name: 'productId', 39 | description: 'Product ID', 40 | type: String 41 | }) 42 | @ApiQuery({ 43 | name: 'totalDistanceMeasured', 44 | description: 'Distance for delivery', 45 | type: String 46 | }) 47 | @ApiQuery({ 48 | name: 'weight', 49 | description: 'Product Weight', 50 | type: String 51 | }) 52 | @ApiQuery({ 53 | name: 'dimension', 54 | description: 'Product dimension(Height,length,width)', 55 | type: String 56 | }) 57 | @ApiResponse({ status: 204, description: 'Out of stock' }) 58 | @ApiResponse({ status: 200, description: 'Ok' }) 59 | // end of swagger defination 60 | 61 | // Pipe methods are used for validation 62 | async getQuote(@Req() req: any, @Query('mode') mode: string, @Query('productId') productId: string, @Query('quantity', ParseIntPipe) quantity: number, 63 | @Query('totalDistanceMeasured',ParseIntPipe) totalDistanceMeasured: number, @Query('weight',ParseIntPipe) weight: number, @Query('dimension') dimension: string, 64 | ): Promise<any> { 65 | const authorization = req.headers.authorization; 66 | const isAuthorized = req.authInfo.checkLocalScope('Supplier'); 67 | // checks for authorization before executing next block, if unauthorized, returns exception 68 | if(isAuthorized){ 69 | return await this.quoteService.checkProductStock(authorization, mode.toUpperCase(), productId, quantity, 70 | weight, totalDistanceMeasured, dimension).then(data => { 71 | return { Cost: data }; 72 | }).catch(error => { 73 | /** 74 | * if error is false, its a out of stock error 75 | */ 76 | if (error === false) { 77 | throw new HttpException('Product Out Of Stock',HttpStatus.NO_CONTENT); 78 | } 79 | console.log(error); 80 | throw new HttpException({"status": 500,"error": "Unable to handle request"}, HttpStatus.INTERNAL_SERVER_ERROR); 81 | }); 82 | }else{ 83 | throw new UnauthorizedException(); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /logistics-service/src/logistics/quote.module.ts: -------------------------------------------------------------------------------- 1 | import { QuoteController } from './quote.controller'; 2 | import { Module } from '@nestjs/common'; 3 | import { HttpModule } from '@nestjs/axios'; 4 | import {QuoteService} from './quote.service'; 5 | @Module({ 6 | imports: [HttpModule], 7 | controllers: [ 8 | QuoteController], 9 | providers: [QuoteService], 10 | }) 11 | export class QuoteModule {} 12 | -------------------------------------------------------------------------------- /logistics-service/src/logistics/quote.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { ServiceCredentials } from '../providers/security-credentials.provider'; 3 | import { destination } from '../providers/destination.provider'; 4 | const axios = require('axios').default; 5 | @Injectable() 6 | export class QuoteService { 7 | processQuote(mode: string, quantity: number, weight: number, totalDistanceMeasured: number, dimension: string) { 8 | return new Promise((resolve, reject) => { 9 | this.getClientToken(ServiceCredentials[0]).then(token => { 10 | let header = { "Authorization": 'Bearer ' + token }; 11 | this.getFreight(header, quantity, weight, totalDistanceMeasured, dimension, mode).then((data: any) => { 12 | console.log("Request Came here"); 13 | resolve(data); 14 | }).catch(error => { 15 | console.log("Error Getting Quote"); 16 | reject(error); 17 | }); 18 | }).catch(error => { 19 | console.log("Error Handling token", error); 20 | reject(error); 21 | }); 22 | }); 23 | } 24 | /** 25 | * Calls the frieght Manager service using this method 26 | * @param authHeader Bearet Token 27 | * @param quantity Quantity represents the weight 28 | */ 29 | async getFreight(authHeader: any, quantity: number, weight: number, totalDistanceMeasured: number, dimension: string, mode: string) { 30 | return new Promise((resolve, reject) => { 31 | destination.then(async destinationObject =>{ 32 | var config = { 33 | method: 'get', 34 | url: destinationObject.url + '/destination-configuration/v1/subaccountDestinations', 35 | headers: { 36 | 'Authorization':'Bearer' + destinationObject.authTokens[0].value 37 | } 38 | }; 39 | let dest = await axios(config).then(function (response) { 40 | return response.data; 41 | }).catch(function (error) { 42 | reject(error); 43 | }); 44 | let url = dest[0].URL + `?transportationmeans=${mode}&weight=${weight}&totalDistanceMeasured=${totalDistanceMeasured}&quantity=${quantity}&dimension=${dimension}`; 45 | this.httpService(url, authHeader).then(data => { 46 | console.log("in quote data part"); 47 | resolve(data.data); 48 | }).catch(error => { 49 | console.log("in Quote error Part"); 50 | console.log(error.response.data); 51 | reject(error.response.data); 52 | }); 53 | }).catch(err => { 54 | reject(err); 55 | }); 56 | }); 57 | } 58 | /** 59 | * This method is used to generate client credentials 60 | * @param clientCredentials XSUAA credentials returned from credentials provider 61 | */ 62 | async getClientToken(clientCredentials: any) { 63 | return new Promise((resolve, reject) => { 64 | const url = `${clientCredentials.url}/oauth/token`; 65 | axios.post(url, `grant_type=client_credentials&client_id=${clientCredentials.clientId}&client_secret=${clientCredentials.clientSecret}`).then((res: any) => { 66 | resolve(res.data.access_token); 67 | }).catch((error: any) => { 68 | console.log(error); 69 | reject(error); 70 | }); 71 | }); 72 | } 73 | /** 74 | * this calls product service to check the stock availablity status 75 | * @param authHeader Authentication Token 76 | * @param item Product ID to be shipped 77 | * @param quantity Number of items 78 | */ 79 | async checkProductStock(authorization: any, mode: string, productId: string, quantity: number, 80 | weight: number, totalDistanceMeasured: number, dimension: string): Promise<any> { 81 | return new Promise((resolve, reject) => { 82 | let url = process.env.product_service + `/stock?productId=${productId}&quantity=${quantity}`; 83 | let header = { "Authorization": authorization }; 84 | this.httpService(url, header).then(data => { 85 | console.log(data.data); 86 | if (data.data === true) { 87 | this.processQuote(mode, quantity, weight, totalDistanceMeasured, dimension).then(data => { 88 | resolve(data); 89 | }).catch(error => { 90 | console.error("in check product Stock"); 91 | reject(error); 92 | }); 93 | } else { 94 | reject(false) 95 | } 96 | }).catch(error => { 97 | reject(error); 98 | }); 99 | }); 100 | } 101 | async httpService(url: string, header: any): Promise<any> { 102 | try { 103 | const request = await axios.get(url, { headers: header }); 104 | return request; 105 | } catch (error) { 106 | throw error; 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /logistics-service/src/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory} from '@nestjs/core'; 2 | import { AppModule } from './app.module'; 3 | import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; 4 | import { getServices, cfServiceCredentials } from '@sap/xsenv'; 5 | 6 | /** 7 | * Security middleware 8 | */ 9 | const xsuaa = getServices({ xsuaa: { tag: 'xsuaa' } }).xsuaa; 10 | import * as passport from 'passport'; 11 | import { JWTStrategy } from '@sap/xssec'; 12 | passport.use(new JWTStrategy(xsuaa)); 13 | 14 | /** 15 | * HANA DB configuration 16 | */ 17 | import * as hana from '@sap/hdbext'; 18 | const hanacreds = cfServiceCredentials({ tag: 'hana' }); 19 | 20 | async function bootstrap() { 21 | const app = await NestFactory.create(AppModule); 22 | /** 23 | * Swagger Defination 24 | */ 25 | const options = new DocumentBuilder() 26 | .setTitle('Logistics Service') 27 | .setDescription('APIs for logistics service') 28 | .setVersion('1.0').addBearerAuth().addTag('Logistics Service') 29 | .build(); 30 | const document = SwaggerModule.createDocument(app, options); 31 | SwaggerModule.setup('api', app, document); 32 | //HANA middleware 33 | app.use(hana.middleware(hanacreds)); 34 | //security 35 | app.use(passport.initialize()); 36 | app.use(passport.authenticate('JWT', { session: false })); 37 | 38 | await app.listen(process.env.PORT || 3000); 39 | } 40 | bootstrap(); 41 | -------------------------------------------------------------------------------- /logistics-service/src/model/quotemodel.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsNotEmpty, IsString, IsNumber, MaxLength, IsEmail } from 'class-validator'; 2 | import { ApiProperty } from '@nestjs/swagger'; 3 | 4 | /** 5 | * Class implementation for freight order 6 | * class validators are used to validate the coming data and datatype using nest.js pipes 7 | * 8 | */ 9 | export class FreightOrder { 10 | //Swagger annotation starts here 11 | @IsNotEmpty() 12 | @IsString() 13 | @ApiProperty({ description: 'Contact Person Name'}) 14 | //End of swagger defincation 15 | contactPerson: string; 16 | 17 | @IsNotEmpty() 18 | @IsString() 19 | @ApiProperty({ description: 'Address' }) 20 | address: string; 21 | 22 | @IsNotEmpty() 23 | @IsString() 24 | @MaxLength(10) 25 | @ApiProperty({ description: 'Phone Number', maxLength: 10 }) 26 | phone: string; 27 | 28 | 29 | @IsNotEmpty() 30 | @IsString() 31 | @MaxLength(2) 32 | @ApiProperty({ description: 'Country Code', maxLength: 2 }) 33 | countryCode: string; 34 | 35 | @IsNotEmpty() 36 | @IsString() 37 | @IsEmail() 38 | @ApiProperty({ description: 'Email' }) 39 | email: string; 40 | 41 | @IsNotEmpty() 42 | @IsNumber() 43 | @ApiProperty({ description: 'Total Distance Measured' }) 44 | totalDistanceMeasured: number; 45 | 46 | @IsNotEmpty() 47 | @IsString() 48 | @ApiProperty({ description: 'productName'}) 49 | productName: string; 50 | 51 | @IsNotEmpty() 52 | @IsString() 53 | @ApiProperty({ description: 'Product ID'}) 54 | productId: string; 55 | 56 | @IsNotEmpty() 57 | @IsString() 58 | @ApiProperty({ description: 'Quantity'}) 59 | quantity: number; 60 | 61 | @IsNotEmpty() 62 | @IsNumber() 63 | @ApiProperty({ description: 'Gross weight' }) 64 | grossWeight: number; 65 | 66 | @IsNotEmpty() 67 | @IsNumber() 68 | @MaxLength(5) 69 | @ApiProperty({ description: 'Transportation Means Type Code', maxLength: 5 }) 70 | transportationMeansType: string; 71 | 72 | @IsNotEmpty() 73 | @IsString() 74 | @MaxLength(4) 75 | @ApiProperty({ description: 'Lifecycle means', maxLength: 4 }) 76 | lifecyclestatus: string; 77 | 78 | @IsNotEmpty() 79 | @IsString() 80 | @MaxLength(8) 81 | @ApiProperty({ description: 'Pickup Date', maxLength: 8 }) 82 | pickupdate: string; 83 | 84 | 85 | @IsNotEmpty() 86 | @IsString() 87 | @MaxLength(8) 88 | @ApiProperty({ description: 'Delivery Date', maxLength: 8 }) 89 | deliverydate: string; 90 | 91 | @IsNotEmpty() 92 | @IsNumber() 93 | @ApiProperty({ description: 'Transportation Charges' }) 94 | transportationCharges: number; 95 | 96 | @IsNotEmpty() 97 | @IsString() 98 | @MaxLength(3) 99 | @ApiProperty({ description: 'Currency Code', maxLength: 3 }) 100 | currencycode: string; 101 | } -------------------------------------------------------------------------------- /logistics-service/src/providers/destination.provider.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Exports destination service 3 | */ 4 | import { useOrFetchDestination } from '@sap-cloud-sdk/connectivity'; 5 | 6 | const destionationObject = useOrFetchDestination({ destinationName: 'freight-manager' }).then(destination => { 7 | return destination; 8 | }).catch(err => { 9 | return err; 10 | }); 11 | export const destination = destionationObject; -------------------------------------------------------------------------------- /logistics-service/src/providers/security-credentials.provider.ts: -------------------------------------------------------------------------------- 1 | import * as xsenv from '@sap/xsenv'; 2 | const xsCredentials = xsenv.cfServiceCredentials({tag: 'xsuaa'}); 3 | /** 4 | * exports client credentials from vcap 5 | */ 6 | export const ServiceCredentials = [{ "clientId": xsCredentials.clientid, "clientSecret": xsCredentials.clientsecret,"url": xsCredentials.url }]; 7 | -------------------------------------------------------------------------------- /logistics-service/systems.json: -------------------------------------------------------------------------------- 1 | { 2 | "systems": [{ 3 | "alias": "EXAMPLE", 4 | "uri": "https://example.com" 5 | }] 6 | } 7 | -------------------------------------------------------------------------------- /logistics-service/test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { INestApplication } from '@nestjs/common'; 3 | import * as request from 'supertest'; 4 | import { AppModule } from './../src/app.module'; 5 | 6 | describe('AppController (e2e)', () => { 7 | let app: INestApplication; 8 | 9 | beforeEach(async () => { 10 | const moduleFixture: TestingModule = await Test.createTestingModule({ 11 | imports: [AppModule], 12 | }).compile(); 13 | 14 | app = moduleFixture.createNestApplication(); 15 | await app.init(); 16 | }); 17 | 18 | it('/ (GET)', () => { 19 | return request(app.getHttpServer()) 20 | .get('/') 21 | .expect(200) 22 | .expect('Hello World!'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /logistics-service/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": [ 3 | "js", 4 | "json", 5 | "ts" 6 | ], 7 | "rootDir": ".", 8 | "testEnvironment": "node", 9 | "testRegex": ".e2e-spec.ts$", 10 | "transform": { 11 | "^.+\\.(t|j)s$": "ts-jest" 12 | }, 13 | "reporters": [ 14 | "default", 15 | [ 16 | "jest-junit", 17 | { 18 | "suiteName": "backend unit tests", 19 | "outputDirectory": "./s4hana_pipeline/reports/backend-integration" 20 | } 21 | ] 22 | ], 23 | "collectCoverage": true, 24 | "coverageReporters": [ 25 | "text", 26 | "cobertura" 27 | ], 28 | "coverageDirectory": "../s4hana_pipeline/reports/coverage-reports/backend-integration" 29 | } -------------------------------------------------------------------------------- /logistics-service/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /logistics-service/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "es2017", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /product-service/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | sourceType: 'module', 6 | }, 7 | plugins: ['@typescript-eslint/eslint-plugin'], 8 | extends: [ 9 | 'plugin:@typescript-eslint/eslint-recommended', 10 | 'plugin:@typescript-eslint/recommended', 11 | 'prettier', 12 | 'prettier/@typescript-eslint', 13 | ], 14 | root: true, 15 | env: { 16 | node: true, 17 | jest: true, 18 | }, 19 | rules: { 20 | '@typescript-eslint/interface-name-prefix': 'off', 21 | '@typescript-eslint/explicit-function-return-type': 'off', 22 | '@typescript-eslint/no-explicit-any': 'off', 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /product-service/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # OS 14 | .DS_Store 15 | 16 | # Tests 17 | /coverage 18 | /.nyc_output 19 | 20 | # IDEs and editors 21 | /.idea 22 | .project 23 | .classpath 24 | .c9/ 25 | *.launch 26 | .settings/ 27 | *.sublime-workspace 28 | 29 | # IDE - VSCode 30 | .vscode/* 31 | !.vscode/settings.json 32 | !.vscode/tasks.json 33 | !.vscode/launch.json 34 | !.vscode/extensions.json 35 | credentials.json 36 | /s4hana_pipeline 37 | /deployment 38 | -------------------------------------------------------------------------------- /product-service/.npmrc: -------------------------------------------------------------------------------- 1 | @sap:registry=https://registry.npmjs.org 2 | -------------------------------------------------------------------------------- /product-service/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /product-service/manifest.yml: -------------------------------------------------------------------------------- 1 | applications: 2 | - name: product-service 3 | path: deployment/ 4 | buildpacks: 5 | - nodejs_buildpack 6 | memory: 256M 7 | command: npm run start:prod 8 | random-route: true 9 | services: 10 | - businessuser-authentication 11 | - nodeapp_db 12 | -------------------------------------------------------------------------------- /product-service/nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "@nestjs/schematics", 3 | "sourceRoot": "src" 4 | } 5 | -------------------------------------------------------------------------------- /product-service/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "product-service", 3 | "version": "0.0.1", 4 | "description": "", 5 | "author": "", 6 | "private": true, 7 | "license": "UNLICENSED", 8 | "scripts": { 9 | "prebuild": "rimraf dist", 10 | "build": "nest build", 11 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", 12 | "start": "nest start", 13 | "start:dev": "nest start --watch", 14 | "start:debug": "nest start --debug --watch", 15 | "start:prod": "node dist/main", 16 | "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", 17 | "test": "jest", 18 | "test:watch": "jest --watch", 19 | "test:cov": "jest --coverage", 20 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", 21 | "test:e2e": "jest --config ./test/jest-e2e.json", 22 | "deploy": "npm run build && sap-cloud-sdk package && cf push", 23 | "ci-build": "npm run build", 24 | "ci-package": "sap-cloud-sdk package --ci", 25 | "ci-integration-test": "jest --ci --config ./test/jest-e2e.json", 26 | "ci-backend-unit-test": "jest --ci" 27 | }, 28 | "dependencies": { 29 | "@nestjs/common": "^9.1.4", 30 | "@nestjs/core": "^9.1.4", 31 | "@nestjs/platform-express": "^9.1.4", 32 | "@nestjs/swagger": "^6.1.2", 33 | "@sap/hdbext": "^7.6.6", 34 | "@sap/xsenv": "^4.2.0", 35 | "@sap/xssec": "^3.6.0", 36 | "passport": "^0.6.0", 37 | "reflect-metadata": "^0.1.13", 38 | "rimraf": "^3.0.2", 39 | "rxjs": "^7.3.1", 40 | "swagger-ui-express": "^4.1.6" 41 | }, 42 | "devDependencies": { 43 | "@compodoc/compodoc": "^1.1.15", 44 | "@nestjs/cli": "^9.1.4", 45 | "@nestjs/schematics": "^9.0.3", 46 | "@nestjs/testing": "^9.1.4", 47 | "@types/express": "^4.17.13", 48 | "@types/jest": "27.0.2", 49 | "@types/node": "^18.15.11", 50 | "@types/supertest": "^2.0.11", 51 | "@typescript-eslint/eslint-plugin": "3.0.2", 52 | "@typescript-eslint/parser": "3.0.2", 53 | "eslint": "^7.32.0", 54 | "eslint-config-prettier": "^8.3.0", 55 | "eslint-plugin-import": "^2.20.1", 56 | "jest": "27.2.4", 57 | "jest-junit": "^13.0.0", 58 | "prettier": "^1.19.1", 59 | "supertest": "^4.0.2", 60 | "ts-jest": "27.0.5", 61 | "ts-loader": "^9.2.6", 62 | "ts-node": "^10.2.1", 63 | "tsconfig-paths": "^3.11.0", 64 | "typescript": "^4.3.5" 65 | }, 66 | "jest": { 67 | "moduleFileExtensions": [ 68 | "js", 69 | "json", 70 | "ts" 71 | ], 72 | "rootDir": "src", 73 | "testRegex": ".spec.ts$", 74 | "transform": { 75 | "^.+\\.(t|j)s$": "ts-jest" 76 | }, 77 | "coverageDirectory": "../s4hana_pipeline/reports/coverage-reports/backend-unit", 78 | "testEnvironment": "node", 79 | "reporters": [ 80 | "default", [ 81 | "jest-junit", 82 | { 83 | "suiteName": "backend unit tests", 84 | "outputDirectory": "./s4hana_pipeline/reports/backend-unit" 85 | } 86 | ] 87 | ], 88 | "collectCoverage": true, 89 | "coverageReporters": [ 90 | "text", 91 | "cobertura" 92 | ] 93 | } 94 | } -------------------------------------------------------------------------------- /product-service/sap-cloud-sdk-analytics.json: -------------------------------------------------------------------------------- 1 | { 2 | "enabled": true, 3 | "salt": "f6936c8b5df78f00c63e803e0dba3a299d32a6898710c6929d475aebe6a86d0d" 4 | } -------------------------------------------------------------------------------- /product-service/src/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '@nestjs/common'; 2 | import { AppService } from './app.service'; 3 | 4 | @Controller() 5 | export class AppController { 6 | constructor(private readonly appService: AppService) {} 7 | 8 | @Get() 9 | getHello(): string { 10 | return this.appService.getHello(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /product-service/src/app.module.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Module } from '@nestjs/common'; 3 | import { AppController } from './app.controller'; 4 | import { AppService } from './app.service'; 5 | import { ProductModule } from './products/product.module'; 6 | import { ProductService } from './products/product.service'; 7 | import { StockService } from './products/stock.service'; 8 | import { StockModule } from './products/stock.module'; 9 | @Module({ 10 | imports: [ 11 | ProductModule, StockModule], 12 | controllers: [AppController], 13 | providers: [AppService, ProductService, StockService], 14 | }) 15 | export class AppModule { } 16 | -------------------------------------------------------------------------------- /product-service/src/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AppService { 5 | getHello(): string { 6 | return 'Hello Product Service!'; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /product-service/src/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory} from '@nestjs/core'; 2 | import { AppModule } from './app.module'; 3 | import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; 4 | import { getServices, cfServiceCredentials } from '@sap/xsenv'; 5 | /** 6 | * Security Configuration 7 | */ 8 | const xsuaa = getServices({ xsuaa: { tag: 'xsuaa' } }).xsuaa; 9 | import * as passport from 'passport'; 10 | import { JWTStrategy } from '@sap/xssec'; 11 | passport.use(new JWTStrategy(xsuaa)); 12 | 13 | /** 14 | * HANA DB configuration 15 | */ 16 | import * as hana from '@sap/hdbext'; 17 | const hanacreds = cfServiceCredentials({ tag: 'hana' }); 18 | 19 | async function bootstrap() { 20 | const app = await NestFactory.create(AppModule); 21 | /** 22 | * Swagger Defination 23 | */ 24 | const options = new DocumentBuilder() 25 | .setTitle('Product Service') 26 | .setDescription('APIs for logistics service') 27 | .setVersion('1.0').addBearerAuth().addTag('Product Service') 28 | .build(); 29 | const document = SwaggerModule.createDocument(app, options); 30 | SwaggerModule.setup('api', app, document); 31 | 32 | //HANA middleware 33 | app.use(hana.middleware(hanacreds)); 34 | 35 | //security middleware 36 | app.use(passport.initialize()); 37 | app.use(passport.authenticate('JWT', { session: false })); 38 | 39 | await app.listen(process.env.PORT || 3000); 40 | } 41 | bootstrap(); 42 | -------------------------------------------------------------------------------- /product-service/src/products/product.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Param, Req, UnauthorizedException} from '@nestjs/common'; 2 | import {ProductService} from './product.service'; 3 | import {ApiBearerAuth, ApiTags,ApiOperation, ApiParam } from '@nestjs/swagger'; 4 | @Controller('getProducts') 5 | export class ProductController { 6 | constructor(private productService: ProductService){} 7 | /** 8 | * Get List of all the products 9 | */ 10 | @Get() 11 | @ApiBearerAuth() 12 | @ApiTags('Product Service') 13 | @ApiOperation({ summary: 'Get list of all Products' }) 14 | getAllProducts(@Req() req: any): any{ 15 | 16 | const isAuthorized = req.authInfo.checkLocalScope('Supplier'); 17 | if(isAuthorized){ 18 | const hanaClient = req.db; 19 | return this.productService.getAllProducts(hanaClient).then(data=>{ 20 | return data; 21 | }).catch(error=>{ 22 | throw(error); 23 | }); 24 | }else{ 25 | throw new UnauthorizedException(); 26 | } 27 | } 28 | 29 | /** 30 | * 31 | * @param id Product ID 32 | */ 33 | @Get(':productId') 34 | @ApiTags('Product Service') 35 | @ApiBearerAuth() 36 | @ApiOperation({summary: 'Returns product details based on product id'}) 37 | @ApiParam({name:'productId',description:'Product Id' }) 38 | getProduct(@Req()req: any,@Param() productId: any): any{ 39 | const isAuthorized = req.authInfo.checkLocalScope('Supplier'); 40 | if(isAuthorized){ 41 | const hanaClient = req.db; 42 | return this.productService.getProductDetails(productId,hanaClient).then(data=>{ 43 | return data; 44 | }).catch(error=>{ 45 | throw(error); 46 | }); 47 | }else{ 48 | throw new UnauthorizedException(); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /product-service/src/products/product.module.ts: -------------------------------------------------------------------------------- 1 | import { ProductService } from './product.service'; 2 | import { ProductController } from './product.controller'; 3 | import { Module } from '@nestjs/common'; 4 | 5 | @Module({ 6 | imports: [], 7 | controllers: [ 8 | ProductController], 9 | providers: [ 10 | ProductService], 11 | }) 12 | export class ProductModule { } 13 | -------------------------------------------------------------------------------- /product-service/src/products/product.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | @Injectable() 3 | export class ProductService { 4 | 5 | /** 6 | * Returns list of all the products 7 | */ 8 | async getAllProducts(hanaClient : any): Promise<any> { 9 | const query = `SELECT * FROM "Products.product"`; 10 | return await this.executeQuery(query, hanaClient).then(data => { 11 | return data; 12 | }).catch(err => { 13 | throw (err); 14 | }); 15 | } 16 | 17 | /** 18 | * 19 | * @param id Product Id 20 | * Returns product detials if product id is passed 21 | */ 22 | async getProductDetails(id: any, hanaClient: any): Promise<any> { 23 | const query = `SELECT * FROM "Products.product" where PRODUCTID='${id.productId}'`; 24 | return await this.executeQuery(query, hanaClient).then(data => { 25 | return data; 26 | }).catch(err => { 27 | throw (err); 28 | }); 29 | } 30 | 31 | /** 32 | * 33 | * @param query HANA query 34 | */ 35 | async executeQuery(query: string, hanaClient: any): Promise<any> { 36 | return new Promise((resolve, reject) => { 37 | hanaClient.exec(query, (err: unknown, result: Object) => { 38 | if (err) reject(err); 39 | resolve(result); 40 | }); 41 | }); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /product-service/src/products/stock.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Query, Put, Req, UnauthorizedException } from '@nestjs/common'; 2 | import { StockService } from './stock.service'; 3 | import { ApiBearerAuth, ApiTags, ApiQuery, ApiOperation } from '@nestjs/swagger'; 4 | @Controller('stock') 5 | export class StockController { 6 | constructor(private stockService: StockService) { } 7 | /** 8 | * 9 | * @param req 10 | * @param productId Product ID 11 | * @param quantity Quantity 12 | */ 13 | @Get() 14 | //Swagger defination starts here 15 | @ApiTags('Product Service') 16 | @ApiBearerAuth() 17 | @ApiOperation({ summary: 'Gets product id, quantity and checks for stock' }) 18 | @ApiQuery({ 19 | name: 'productId', 20 | description: 'Id of the product', 21 | type: String 22 | }) 23 | @ApiQuery({ 24 | name: 'quantity', 25 | description: 'Quantity to be shipped', 26 | type: Number 27 | }) 28 | // end of swagger defination 29 | 30 | checkStock(@Req() req: any, @Query('productId') productId: string, @Query('quantity') quantity: number): any { 31 | const isAuthorized = req.authInfo.checkLocalScope('Supplier'); 32 | if (isAuthorized) { 33 | const hanaClient = req.db; 34 | return this.stockService.checkStock(productId, quantity, hanaClient); 35 | } else { 36 | throw new UnauthorizedException(); 37 | } 38 | } 39 | 40 | /** 41 | * Update stock section 42 | * @param productId product id 43 | * @param quantity quantity 44 | */ 45 | @Put() 46 | @ApiTags('Product Service') 47 | @ApiBearerAuth() 48 | @ApiOperation({ summary: 'Gets product id, quantity and checks for stock' }) 49 | @ApiQuery({ 50 | name: 'productId', 51 | description: 'Id of the product', 52 | type: String 53 | }) 54 | @ApiQuery({ 55 | name: 'quantity', 56 | description: 'Quantity to be shipped', 57 | type: Number 58 | }) 59 | updateStock(@Req() req: any, @Query('productId') productId: string, @Query('quantity') quantity: number): any { 60 | const isAuthorized = req.authInfo.checkLocalScope('Supplier'); 61 | if (isAuthorized) { 62 | const hanaClient = req.db; 63 | return this.stockService.updateStock(productId, quantity, hanaClient); 64 | } else { 65 | throw new UnauthorizedException(); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /product-service/src/products/stock.module.ts: -------------------------------------------------------------------------------- 1 | import { StockService } from './stock.service'; 2 | import { StockController } from './stock.controller'; 3 | import { Module } from '@nestjs/common'; 4 | 5 | @Module({ 6 | imports: [], 7 | controllers: [ 8 | StockController], 9 | providers: [ 10 | StockService], 11 | }) 12 | export class StockModule { } 13 | -------------------------------------------------------------------------------- /product-service/src/products/stock.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | @Injectable() 3 | export class StockService { 4 | /** 5 | * Checks stock. Return true is the requested quantity is greater or equal to the required stock 6 | * 7 | * @param productId product id 8 | * @param quantity quantity to be shipped 9 | */ 10 | async checkStock(productId: string, quantity: number, hanaClient: any): Promise<any> { 11 | let query = `SELECT "QUANTITY" FROM "Products.stock" where PRODUCTID='${productId}'`; 12 | return await this.executeQuery(query,hanaClient).then(stock => { 13 | if (stock[0].QUANTITY >= quantity){ 14 | return true; 15 | }else { 16 | return false; 17 | } 18 | }).catch(err => { 19 | throw err; 20 | }); 21 | } 22 | /** 23 | * this method is used to update the quantity value 24 | * @param productId product id 25 | * @param quantity Quantity 26 | */ 27 | async updateStock(productId: string, quantity: number, hanaClient: any): Promise<any> { 28 | let query = `Update "Products.stock" set QUANTITY=QUANTITY-${quantity} where PRODUCTID='${productId}'`; 29 | return await this.executeQuery(query,hanaClient).then(stock => { 30 | return 'Stock Updated'; 31 | }).catch(err => { 32 | throw err; 33 | }); 34 | } 35 | /** 36 | * Query Execution 37 | * @param query SQL query 38 | */ 39 | async executeQuery(query: string, hanaClient: any): Promise < any > { 40 | return new Promise((resolve, reject) => { 41 | hanaClient.exec(query, (err: unknown, result: Object) => { 42 | if (err) reject(err); 43 | resolve(result); 44 | }); 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /product-service/systems.json: -------------------------------------------------------------------------------- 1 | { 2 | "systems": [{ 3 | "alias": "EXAMPLE", 4 | "uri": "https://example.com" 5 | }] 6 | } 7 | -------------------------------------------------------------------------------- /product-service/test/app.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AppController } from '../src/app.controller'; 3 | import { AppService } from '../src/app.service'; 4 | 5 | describe('AppController', () => { 6 | let appController: AppController; 7 | 8 | beforeEach(async () => { 9 | const app: TestingModule = await Test.createTestingModule({ 10 | controllers: [AppController], 11 | providers: [AppService], 12 | }).compile(); 13 | 14 | appController = app.get<AppController>(AppController); 15 | }); 16 | 17 | describe('root', () => { 18 | it('should return "Hello World!"', () => { 19 | expect(appController.getHello()).toBe('Hello World!'); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /product-service/test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { INestApplication } from '@nestjs/common'; 3 | import * as request from 'supertest'; 4 | import { AppModule } from './../src/app.module'; 5 | 6 | describe('AppController (e2e)', () => { 7 | let app: INestApplication; 8 | 9 | beforeEach(async () => { 10 | const moduleFixture: TestingModule = await Test.createTestingModule({ 11 | imports: [AppModule], 12 | }).compile(); 13 | 14 | app = moduleFixture.createNestApplication(); 15 | await app.init(); 16 | }); 17 | 18 | it('/ (GET)', () => { 19 | return request(app.getHttpServer()) 20 | .get('/') 21 | .expect(200) 22 | .expect('Hello World!'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /product-service/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": [ 3 | "js", 4 | "json", 5 | "ts" 6 | ], 7 | "rootDir": ".", 8 | "testEnvironment": "node", 9 | "testRegex": ".e2e-spec.ts$", 10 | "transform": { 11 | "^.+\\.(t|j)s$": "ts-jest" 12 | }, 13 | "reporters": [ 14 | "default", 15 | [ 16 | "jest-junit", 17 | { 18 | "suiteName": "backend unit tests", 19 | "outputDirectory": "./s4hana_pipeline/reports/backend-integration" 20 | } 21 | ] 22 | ], 23 | "collectCoverage": true, 24 | "coverageReporters": [ 25 | "text", 26 | "cobertura" 27 | ], 28 | "coverageDirectory": "../s4hana_pipeline/reports/coverage-reports/backend-integration" 29 | } -------------------------------------------------------------------------------- /product-service/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /product-service/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "es2017", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true, 14 | "resolveJsonModule": true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /security-config/xs-security.json: -------------------------------------------------------------------------------- 1 | { 2 | "xsappname": "businessuser-authentication", 3 | "tenant-mode": "dedicated", 4 | "description": "Security profile of logistics service", 5 | "authorities":["$ACCEPT_GRANTED_AUTHORITIES"], 6 | "scopes": [ 7 | { 8 | "name": "$XSAPPNAME.Supplier", 9 | "description": "Display Suppliers" 10 | } 11 | ], 12 | "role-templates": [ 13 | { 14 | "name": "Supplier", 15 | "description": "View Suppliers", 16 | "scope-references": [ 17 | "$XSAPPNAME.Supplier" 18 | ] 19 | } 20 | ], 21 | "oauth2-configuration": { 22 | "redirect-uris": [ 23 | "https://*.cfapps.eu10-004.hana.ondemand.com/**", 24 | "https://*.cfapps.eu10.hana.ondemand.com/**" 25 | ] 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | package-lock.json -------------------------------------------------------------------------------- /test/config.js: -------------------------------------------------------------------------------- 1 | const logistics_cred = require('./logistic_env') 2 | const product_cred = require('./product_env') 3 | const freight_cred = require('./freight_env') 4 | const vcap = logistics_cred.system_env_json.VCAP_SERVICES; 5 | const vcap2 = freight_cred.system_env_json.VCAP_SERVICES; 6 | const logistics_appenv = logistics_cred.application_env_json.VCAP_APPLICATION; 7 | const product_appenv = product_cred.application_env_json.VCAP_APPLICATION; 8 | const freight_appenv = freight_cred.application_env_json.VCAP_APPLICATION; 9 | 10 | 11 | module.exports = { 12 | "token_url": vcap.xsuaa[0].credentials.url + '/oauth/token', 13 | "logistic_service_url": 'https://' + logistics_appenv.application_uris[0], 14 | "product_service_url": 'https://' + product_appenv.application_uris[0], 15 | "freight_service_url": 'https://' + freight_appenv.application_uris[0], 16 | "xsuaa": { 17 | "grant_type": "password", 18 | "client_id": vcap.xsuaa[0].credentials.clientid, 19 | "client_secret": vcap.xsuaa[0].credentials.clientsecret, 20 | "username": process.env.pusername, 21 | "password": process.env.puserpwd 22 | }, 23 | "freight_service_config": { 24 | "grant_type": "client_credentials", 25 | "client_id": vcap.xsuaa[0].credentials.clientid, 26 | "client_secret": vcap.xsuaa[0].credentials.clientsecret 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "integration_test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "test": "jest" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "dependencies": { 11 | "node-fetch": "^2.6.1", 12 | "qs": "^6.10.1" 13 | }, 14 | "devDependencies": { 15 | "jest": "^27.0.6" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/test-suite.js: -------------------------------------------------------------------------------- 1 | const config = require('./config') 2 | const util = require('./util') 3 | 4 | let xsuaa_access_token, access_token_freight_service; 5 | 6 | async function getAuthTokenXSUAA(){ 7 | const req_url = config.token_url 8 | const req_headers = { 'Content-Type': 'application/x-www-form-urlencoded' } 9 | console.log('REQUEST URL: POST', req_url) 10 | console.log('REQUEST HEADERS:', req_headers) 11 | try{ 12 | const response = await util.requestHandler({ 13 | url: req_url, 14 | method: 'POST', 15 | body: util.urlEncodeParams(config.xsuaa), 16 | headers: req_headers 17 | }) 18 | console.log('RESPONSE STATUS:', response.status) 19 | const json = await response.json() 20 | console.log('RESPONSE BODY:',json) 21 | if(json.access_token) xsuaa_access_token = json.access_token 22 | return json 23 | } catch(err) { 24 | return err 25 | } 26 | } 27 | 28 | async function getProducts(){ 29 | const req_url = config.product_service_url+'/getProducts' 30 | const req_headers = { 'Authorization':'Bearer '+ xsuaa_access_token } 31 | console.log('REQUEST URL: GET', req_url) 32 | try{ 33 | const response = await util.requestHandler({ 34 | url: req_url, 35 | method: 'GET', 36 | headers: req_headers 37 | }) 38 | console.log('RESPONSE STATUS:', response.status) 39 | const json = await response.json() 40 | console.log('RESPONSE BODY:',json) 41 | return json 42 | } 43 | catch(err) { 44 | return err 45 | } 46 | } 47 | 48 | async function getStock(){ 49 | let req_url = config.product_service_url+'/stock' 50 | const req_headers = { 'Authorization':'Bearer '+ xsuaa_access_token } 51 | let params = { productId: 'HT-1000', quantity: 1 } 52 | req_url = util.parameteriseUrl(req_url, params) 53 | console.log('REQUEST URL: GET', req_url) 54 | try { 55 | const response = await util.requestHandler({ 56 | url: req_url, 57 | method: 'GET', 58 | headers: req_headers 59 | }) 60 | console.log('RESPONSE STATUS:', response.status) 61 | const json = await response.json() 62 | console.log('RESPONSE BODY:',json) 63 | return json 64 | } 65 | catch(err){ 66 | return err 67 | } 68 | } 69 | 70 | async function getQuote(){ 71 | let req_url = config.logistic_service_url+'/getQuote' 72 | const req_headers = { 'Authorization':'Bearer '+ xsuaa_access_token } 73 | let params = { 74 | mode: 'RAIL', 75 | productId: 'HT-1000', 76 | quantity: 1, 77 | totalDistanceMeasured: 50, 78 | weight: 0.4, 79 | dimension: '0.2410,0.1050,0.1190' 80 | } 81 | req_url = util.parameteriseUrl(req_url,params) 82 | console.log('REQUEST URL: GET', req_url) 83 | try{ 84 | const response = await util.requestHandler({ 85 | url: req_url, 86 | method: 'GET', 87 | headers: req_headers 88 | }) 89 | console.log('RESPONSE STATUS:', response.status) 90 | let json; 91 | if(response.status == '200') json = await response.json() 92 | else json = { 'error' : 'Product is out of stock'} 93 | console.log('RESPONSE BODY:',json) 94 | return json 95 | } 96 | catch(err){ 97 | return err 98 | } 99 | } 100 | 101 | async function createOrder(){ 102 | const req_url = config.logistic_service_url+'/order' 103 | const req_headers = { 104 | 'Content-Type': 'application/json', 105 | 'Authorization': 'Bearer '+xsuaa_access_token 106 | } 107 | const req_body = { 108 | "contactPerson":"Steve", 109 | "address":"444 ABC TOWN, MUNICH", 110 | "phone":"9876543210", 111 | "countryCode":"DU", 112 | "email":"steve.wozniak@sap.com", 113 | "totalDistanceMeasured":50, 114 | "productName":"ADSL progress T1", 115 | "productId":"HT-1117", 116 | "quantity":1, 117 | "grossWeight":0.4, 118 | "transportationMeansType":"RAIL", 119 | "lifecyclestatus":"A", 120 | "pickupdate":"20200721", 121 | "deliverydate":"20200721", 122 | "transportationCharges":970, 123 | "currencycode":"EUR" 124 | } 125 | console.log('REQUEST URL: POST', req_url) 126 | console.log('REQUEST BODY:', req_body) 127 | try{ 128 | const response = await util.requestHandler({ 129 | url: req_url, 130 | method: 'POST', 131 | headers: req_headers, 132 | body: JSON.stringify(req_body) 133 | }) 134 | console.log('RESPONSE STATUS:', response.status) 135 | const text = await response.text() 136 | console.log('RESPONSE BODY:',text) 137 | return text 138 | } 139 | catch(err){ 140 | return err 141 | } 142 | } 143 | 144 | async function updateStock(){ 145 | let req_url = config.product_service_url+'/stock' 146 | const req_headers = { 147 | 'Content-Type': 'application/json', 148 | 'Authorization': 'Bearer '+xsuaa_access_token 149 | } 150 | let params = { 151 | productId : 'HT-1000', 152 | quantity : 1 153 | } 154 | req_url = util.parameteriseUrl(req_url,params) 155 | console.log('REQUEST URL: PUT', req_url) 156 | try{ 157 | const response = await util.requestHandler({ 158 | url: req_url, 159 | method: 'PUT', 160 | headers: req_headers 161 | }) 162 | console.log('RESPONSE STATUS:', response.status) 163 | const text = await response.text() 164 | console.log('RESPONSE BODY:',text) 165 | return text 166 | } 167 | catch(err){ 168 | return err 169 | } 170 | } 171 | 172 | async function getAuthTokenFreightService(){ 173 | const req_url = config.token_url 174 | const req_headers = { 'Content-Type': 'application/x-www-form-urlencoded' } 175 | console.log('REQUEST URL: POST', req_url) 176 | console.log('REQUEST HEADERS:', req_headers) 177 | try{ 178 | const response = await util.requestHandler({ 179 | url: req_url, 180 | method: 'POST', 181 | body: util.urlEncodeParams(config.freight_service_config), 182 | headers: req_headers 183 | }) 184 | console.log('RESPONSE STATUS:', response.status) 185 | const json = await response.json() 186 | console.log('RESPONSE BODY:',json) 187 | if(json.access_token) access_token_freight_service = json.access_token 188 | return json 189 | } 190 | catch(err){ 191 | return err 192 | } 193 | } 194 | 195 | async function checkFreightService(){ 196 | let req_url = config.freight_service_url+'/' 197 | const req_headers = { 'Authorization':'Bearer '+ access_token_freight_service } 198 | let params = { 199 | transportationmeans: 'RAIL', 200 | quantity: 1, 201 | totalDistanceMeasured: 50, 202 | weight: 0.4, 203 | dimension: '0.2410,0.1050,0.1190' 204 | } 205 | req_url = util.parameteriseUrl(req_url,params) 206 | console.log('REQUEST URL: GET', req_url) 207 | try{ 208 | const response = await util.requestHandler({ 209 | url: req_url, 210 | method: 'GET', 211 | headers: req_headers 212 | }) 213 | console.log('RESPONSE STATUS:', response.status) 214 | const text = await response.text() 215 | console.log('RESPONSE BODY:',text) 216 | return text 217 | } 218 | catch(err){ 219 | return err 220 | } 221 | } 222 | 223 | module.exports = { getAuthTokenXSUAA, getProducts, getStock, getQuote, createOrder, updateStock, getAuthTokenFreightService, checkFreightService } -------------------------------------------------------------------------------- /test/test-suite.test.js: -------------------------------------------------------------------------------- 1 | const tests = require('./test-suite') 2 | jest.setTimeout(30000) 3 | 4 | describe('Access Tokens', () => { 5 | test('get access token for xsuaa', async () => { 6 | console.log('TEST 1 : Get access token for XSUAA') 7 | const result = await tests.getAuthTokenXSUAA() 8 | console.log('EXPECTED RESULT : XSUAA Access Token') 9 | if(result.error) console.error('ACTUAL RESULT: Issue :',result.error) 10 | else if(result.access_token) console.log('ACTUAL RESULT: XSUAA Access Token') 11 | else console.error('ACTUAL RESULT : Error :',result) 12 | expect(result).toMatchObject({ 13 | "access_token": expect.any(String), 14 | "token_type": "bearer", 15 | "id_token": expect.any(String), 16 | "refresh_token": expect.any(String), 17 | "expires_in": expect.any(Number), 18 | "scope": expect.any(String), 19 | "jti": expect.any(String) 20 | }) 21 | }) 22 | }) 23 | 24 | describe('Products', () => { 25 | test('get products', async () => { 26 | console.log('TEST 2 : Get products') 27 | const result = await tests.getProducts() 28 | console.log('EXPECTED RESULT : Products fetched') 29 | if(result.error) console.error('ACTUAL RESULT: Issue :',result.error) 30 | else if(Array.isArray(result) && result.length > 0) console.log('ACTUAL RESULT: Products fetched') 31 | else if(Array.isArray(result) && result.length <= 0) console.log('ACTUAL RESULT: No products fetched') 32 | else console.error('ACTUAL RESULT : Error :',result) 33 | expect(result).toEqual(expect.arrayContaining([ 34 | expect.objectContaining({ 35 | "PRODUCTID": expect.any(String), 36 | "PRODUCTNAME": expect.any(String), 37 | "CURRENCYCODE": expect.any(String), 38 | "CATEGORY": expect.any(String), 39 | "WEIGHT": expect.any(String), 40 | "WEIGHTUNIT": expect.any(String), 41 | "SHORTDESCRIPTION": expect.any(String), 42 | "PICTUREURL": expect.any(String), 43 | "PRICE": expect.any(String), 44 | "DIMENSIONWIDTH": expect.any(String), 45 | "DIMENSIONDEPTH": expect.any(String), 46 | "DIMENSIONHEIGHT": expect.any(String), 47 | "DIMENSIONUNIT": expect.any(String) 48 | }) 49 | ])) 50 | }) 51 | 52 | test('get stock', async () => { 53 | console.log('TEST 3 : Get Stock') 54 | const result = await tests.getStock() 55 | console.log('EXPECTED RESULT : Product quantity available') 56 | if(result.error) console.error('ACTUAL RESULT: Issue :',result.error) 57 | else if(result) console.log('ACTUAL RESULT: Product quantity available') 58 | else if(!result) console.log('ACTUAL RESULT: Product quantity not in stock') 59 | else console.error('ACTUAL RESULT : Error :',result) 60 | expect(result).toBeTruthy() 61 | }) 62 | }) 63 | 64 | describe('Quotations', () => { 65 | test('get quote', async () => { 66 | console.log('TEST 4 : Get quotation amount') 67 | const result = await tests.getQuote() 68 | console.log('EXPECTED RESULT : Quotation Amount is 970') 69 | if(result.error) console.error('ACTUAL RESULT: Issue :',result.error) 70 | else if(result.Cost) console.log('ACTUAL RESULT: Quotation Amount is '+result.Cost) 71 | else console.error('ACTUAL RESULT : Error :',result) 72 | expect(result).toMatchObject({ "Cost": '970' }) 73 | }) 74 | }) 75 | 76 | describe('Orders', () => { 77 | test('create order', async () => { 78 | console.log('TEST 5 : Create Order') 79 | const result = await tests.createOrder() 80 | console.log('EXPECTED RESULT : Order Created') 81 | if(result == 'Order Created') console.log('ACTUAL RESULT: Order Created') 82 | else if(result.includes('error')){ 83 | const res = JSON.parse(result) 84 | console.error('ACTUAL RESULT: Issue :',res.error) 85 | } 86 | else console.error('ACTUAL RESULT : Error :',result) 87 | expect(result).toBe('Order Created') 88 | }) 89 | 90 | test('update stock', async () => { 91 | console.log('TEST 6 : Update Stock') 92 | const result = await tests.updateStock() 93 | console.log('EXPECTED RESULT : Stock Updated') 94 | if(result == 'Stock Updated') console.log('ACTUAL RESULT: Stock Updated') 95 | else if(result.includes('error')){ 96 | const res = JSON.parse(result) 97 | console.error('ACTUAL RESULT: Issue :',res.error) 98 | } 99 | else console.error('ACTUAL RESULT : Error :',result) 100 | expect(result).toBe('Stock Updated') 101 | }) 102 | }) 103 | 104 | describe('Freight Manager', () => { 105 | test('get access token for freight service', async() => { 106 | console.log('TEST 7 : Get access token for Freight Service') 107 | const result = await tests.getAuthTokenFreightService() 108 | console.log('EXPECTED RESULT : XSUAA Access Token for Freight Service') 109 | if(result.error) console.error('ACTUAL RESULT: Issue :',result.error) 110 | else if(result.access_token) console.log('ACTUAL RESULT: XSUAA Access Token for Freight Service') 111 | else console.error('ACTUAL RESULT : Error :',result) 112 | expect(result).toMatchObject({ 113 | "access_token": expect.any(String), 114 | "token_type": "bearer", 115 | "expires_in": expect.any(Number), 116 | "scope": expect.any(String), 117 | "jti": expect.any(String) 118 | }) 119 | }) 120 | 121 | test('check freight service', async () => { 122 | console.log('TEST 8 : Check Freight Service') 123 | const result = await tests.checkFreightService() 124 | console.log('EXPECTED RESULT : Quotation Amount is 970') 125 | if(result.includes('error')){ 126 | const res = JSON.parse(result) 127 | console.error('ACTUAL RESULT: Issue :',res.error) 128 | } 129 | else if(result) console.log('ACTUAL RESULT: Quotation Amount is '+result) 130 | else console.error('ACTUAL RESULT : Error :',result) 131 | expect(result).toBe('970') 132 | }) 133 | }) 134 | -------------------------------------------------------------------------------- /test/util.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const fetch = require('node-fetch'); 3 | const qs = require('qs'); 4 | 5 | class Util { 6 | 7 | static urlEncodeParams(params){ 8 | return qs.stringify(params) 9 | } 10 | 11 | static parameteriseUrl(url,params){ 12 | params = this.urlEncodeParams(params) 13 | return url+'?'+params 14 | } 15 | 16 | static async requestHandler(options){ 17 | try { 18 | let res = await fetch(options.url, { 19 | method: options.method, 20 | headers: options.headers, 21 | body: options.body 22 | }) 23 | return res; 24 | 25 | } catch (err) { 26 | throw err; 27 | } 28 | } 29 | } 30 | 31 | module.exports = Util --------------------------------------------------------------------------------