diff --git a/LICENSE b/LICENSE index 8dada3e..f3bf6f1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ - Apache License + + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -173,29 +174,4 @@ incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. + END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/README.md b/README.md index bc61232..cb3fae7 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,12 @@ Clone the Git [repository](https://github.com/SAP/cloud-espm-v2.git) or download # 1. Quick start guide ### Setting up the developer environment -1. Install [SAP JVM 7.*](https://tools.hana.ondemand.com/#cloud) or Java JDK 1.7 and setup the JAVA_HOME and PATH environment variables in your local machine -2. Install [Eclipse](https://help.hana.ondemand.com/help/frameset.htm?761374e5711e1014839a8273b0e91070.html). Please download Eclipse Mars +1. Install [SAP JVM 8.*](https://tools.hana.ondemand.com/#cloud) or Java JDK 1.8 and setup the JAVA_HOME and PATH environment variables in your local machine +2. Install [Eclipse](https://help.hana.ondemand.com/help/frameset.htm?761374e5711e1014839a8273b0e91070.html). Please download Eclipse Neon 3. [Install SAP Development Tools for Eclipse](https://help.hana.ondemand.com/help/frameset.htm?76137a37711e1014839a8273b0e91070.html) -4. Install the [SAP HANA Cloud SDK](https://help.hana.ondemand.com/help/frameset.htm?7613843c711e1014839a8273b0e91070.html). Please download Java EE 6 Web Profile SDK -5. [Setup the Runtime Environment](https://help.hana.ondemand.com/help/frameset.htm?7613f000711e1014839a8273b0e91070.html). please use the Java EE 6 Web Profile section in the above document -6. Signup for [HCP Trial account](https://hcp.sap.com/developers.html#section_4) +4. Install the [SAP HANA Cloud SDK](https://help.hana.ondemand.com/help/frameset.htm?7613843c711e1014839a8273b0e91070.html). Please download Java Web Tomcat 8 SDK +5. Use Java Web Tomcat 8 Runtime Environment as described in [Setup the Runtime Environment](https://help.hana.ondemand.com/help/frameset.htm?7613f000711e1014839a8273b0e91070.html) document +6. Signup for [HCP Trial account](https://hcp.sap.com/developers.html#section_4) if you don't have HCP Trial Account ### Build the application and deploy Below are the Steps to build and run espm application. @@ -34,7 +34,7 @@ Below are the Steps to build and run espm application. 7.Bind the database to espm application and start espm application ``` -1.Git configuration in Eclipse +#### 1.Git configuration in Eclipse - From the Eclipse IDE main menu, choose Window > Preferences - Enter git in the filter field in the top-left corner. - Navigate to Team > Git > Configuration and select the Configuration node and add the following configuration @@ -43,7 +43,7 @@ Below are the Steps to build and run espm application. **Note! For most people the proxy value doesn’t need to be set but if you are working behind a proxy, then it should be set as per you environment** -2.Maven configuration +#### 2.Maven configuration - From the Eclipse IDE main menu, choose Window > Preferences - Enter maven in the filter field in the top-left corner - Navigate to Maven > User Settings and select the User Settings node @@ -80,7 +80,7 @@ Below are the Steps to build and run espm application. ``` -3.Clone Git repository and import Maven project +#### 3.Clone Git repository and import Maven project - Open https://github.com/SAP/cloud-espm-v2 with your web browser - Click on the Copy to clipboard so that the Git repository URL of the opened cloud-basecamp GitHub repository is copied to your clipboard. @@ -97,14 +97,14 @@ Below are the Steps to build and run espm application. - Click on Finish so that the remote cloud-basecamp Git repository (source code) is cloned to the local location specified on the last wizard page. - In Eclipse, open File->Import->Existing Maven projects. -4.Update dependencies and build Maven project +#### 4.Update dependencies and build Maven project - Instruction to run update dependencies for the Maven project - Right click on the web project in ESPM > and choose Maven > Click on Update Project - Note! you need to modify the parent pom.xml for certain property values depending on your environment: - local.server.proxy.settings - comment this out if you are not behind a proxy server. Else update your proxy settings here - browser.proxy.settings - comment this out if your browser is not using a proxy. Else update your browser proxy settings here - - sap.cloud.sdk.version - The SAP HANA Cloud Platform SDK for Java EE 6 Web Profile version that you intend to run the application with. the minimum version supported is 2.87.10 + - sap.cloud.sdk.version - The SAP HANA Cloud Platform SDK for Java Web Tomcat 8 version that you intend to run the application with. the minimum version supported is 3.22.10 - olingo.version - The Apache Olingo version that you intend the application to run with. The minimum version supported is 2.0.6 The application can be built with the maven command to the parent pom.xml @@ -115,14 +115,14 @@ Below are the Steps to build and run espm application. **The unit tests and the integration tests are run by default when building the project with goal "clean install"** -5.Deploy the application on local Cloud Runtime +#### 5.Deploy the application on local Cloud Runtime -i)Run the application in HCP Java EE 6 Web Profile Server +i)Run the application in HCP Java Web Tomcat 8 Server - Right click on the web project in ESPM > and choose the Run on Server option ![Run ESPM Locally](/docs/images/RunESPM1.png?raw=true) -- Make sure that Manually define a new server is selected and choose SAP > Java EE 6 Web Profile Server as server type. Leave all other settings unchanged and choose Finish +- Make sure that Manually define a new server is selected and choose SAP > Java Web Tomcat 8 Server as server type. Leave all other settings unchanged and choose Finish ![Run ESPM Finish](/docs/images/RunESPM2.png?raw=true) - Now a local server is started that has your espm application deployed. @@ -140,12 +140,26 @@ ii)Create Users and Assign Role - The eCommerce site can be accessed via the URL: https://localhost:\/espm-cloud-web/webshop - The Retailer UI can be accessed via the URL: https://localhost:\/espm-cloud-web/retailer -6.Deploy the application on SAP HCP via the cockpit +#### 6.Deploy the application on SAP HCP via the cockpit **Note! The application name must be "espm", else the above URL will change based on the application name given during deployment** - Deploy the application in your SAP HANA Cloud Platform Trial account. - - Note! If you deploy with the console client, make sure to specify the --java-version parameter with value 7. Note! The application name must be espm. + +1.Go to HCP Cockpit --> Click on Java Application under Applications --> Click on Deploy Application + +![HCP Cockpit](/docs/images/HCPCockpit.png?raw=true) + + +2.Add War File Location, Give Application Name "espm" ,select Runtime Name "Java Web Tomcat 8" and JVM Version "JRE 8" + +![HCP Deploy](/docs/images/HCPDeploy.png?raw=true) + + +3.After Successful Deployment , Click on Start + +![Deployed](/docs/images/Deployed.png?raw=true) + - Configure the application role assignments from the [cockpit](https://help.hana.ondemand.com/help/frameset.htm?db8175b9d976101484e6fa303b108acd.html). You basically need to add the "Retailer" role to your SAP HANA Cloud Platform user to access the Retailer UI You can access the application from the URL @@ -156,7 +170,7 @@ ii)Create Users and Assign Role **Note! The application name must be "espm", else the above URL will change bsaed on the application name given during deployment** -7.Bind the database to espm application and start espm application +#### 7.Bind the database to espm application and start espm application Below is the process to bind the database to the java application in HCP trial account using a Shared HANA database @@ -276,3 +290,4 @@ Copyright 2016 SAP SE Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. You may obtain a copy of the License in the LICENSE file, or at: [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0) Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + diff --git a/docs/demoscript/Retailer_SalesOrderApprovalREADME.md b/docs/demoscript/Retailer_SalesOrderApprovalREADME.md index 7349d31..41ea627 100644 --- a/docs/demoscript/Retailer_SalesOrderApprovalREADME.md +++ b/docs/demoscript/Retailer_SalesOrderApprovalREADME.md @@ -2,22 +2,21 @@ Enterprise Sales Procurement Model (ESPM) Sample Application - Retailer - Sales ========================================================================================================== 1. Open ESPM Retailer URL in the browser https://espmxxxxxxxtrial.hanatrial.ondemand.com/espm-cloud-web/retailer/ - ![ESPM1](/docs/demoscript/retailerimages/LaunchRetailer.png?raw=true) -2. Click on tile “Approve sales orders” to view the list of sales orders. +2. Click on tile “Approve sales orders” to view the list of sales orders. ![ESPM2](/docs/demoscript/retailerimages/2.ClickSalesOrderTile.png?raw=true) -3. Select Sales Order item from the sales orders list to view its details. +3. Select Sales Order item from the sales orders list to view its details. ![ESPM3](/docs/demoscript/retailerimages/3.SelectSalesOrder.png?raw=true) -4. The details of the sales order is available in the details view. Click on Approve button on the bottom to approve the sales order. Likewise, clicking on the Reject button will reject the sales order. +4. The details of the sales order is available in the details view. Click on Approve button on the bottom to approve the sales order. Likewise, clicking on the Reject button will reject the sales order. ![ESPM4](/docs/demoscript/retailerimages/4.DetailsfoSalesOrder.png?raw=true) -5. On selecting approve, a message box to confirm approval is shown. Click on “Ok” button to confirm sales order approval. +5. On selecting approve, a message box to confirm approval is shown. Click on “Ok” button to confirm sales order approval. ![ESPM5](/docs/demoscript/retailerimages/5.ApproveSalesOrderr.png?raw=true) -6. The Sales Order is approved and a message is shown for confirmation. +6. The Sales Order is approved and a message is shown for confirmation. ![ESPM6](/docs/demoscript/retailerimages/6.SalesOrderApproved.png?raw=true) diff --git a/docs/demoscript/Retailer_StockUpdateREADME.md b/docs/demoscript/Retailer_StockUpdateREADME.md index 4071c40..1d266a3 100644 --- a/docs/demoscript/Retailer_StockUpdateREADME.md +++ b/docs/demoscript/Retailer_StockUpdateREADME.md @@ -1,23 +1,22 @@ Enterprise Sales Procurement Model (ESPM) Sample Application - Retailer - Stock Update Demo Script ================================================================================================== - 1. Open ESPM Retailer URL in the browser https://espmxxxxxxxtrial.hanatrial.ondemand.com/espm-cloud-web/retailer/ - +1. Open ESPM Retailer URL in the browser https://espmxxxxxxxtrial.hanatrial.ondemand.com/espm-cloud-web/retailer/ ![ESPM1](/docs/demoscript/retailerimages/LaunchRetailer.png?raw=true) -2. Click on tile “Stock availability” to check the product stock information availability. +2. Click on tile “Stock availability” to check the product stock information availability. ![ESPM2](/docs/demoscript/retailerimages/1.ClickStockTile.png?raw=true) -3. The list of products and its stock information is shown. To update the minimum required stock information, click on the link against Items in Stock/Target. +3. The list of products and its stock information is shown. To update the minimum required stock information, click on the link against Items in Stock/Target. ![ESPM3](/docs/demoscript/retailerimages/2.updateproductstock.png?raw=true) -4. In the popup window, you can update the Minimum stock level information. Click on Submit button. +4. In the popup window, you can update the Minimum stock level information. Click on Submit button. ![ESPM4](/docs/demoscript/retailerimages/3.SetMinimumStock.png?raw=true) -5. If the Minimum stock level information is greater that items in stock, the status is shown in red. +5. If the Minimum stock level information is greater that items in stock, the status is shown in red. ![ESPM5](/docs/demoscript/retailerimages/5.ApproveSalesOrderr.png?raw=true) -6. The Sales Order is approved and a message is shown for confirmation. +6. The Sales Order is approved and a message is shown for confirmation. ![ESPM6](/docs/demoscript/retailerimages/4.StockinformationUpdated.png?raw=true) diff --git a/docs/demoscript/WebshopREADME.md b/docs/demoscript/WebshopREADME.md index 41b0b58..6f1ec8c 100644 --- a/docs/demoscript/WebshopREADME.md +++ b/docs/demoscript/WebshopREADME.md @@ -2,33 +2,32 @@ Enterprise Sales Procurement Model (ESPM) Sample Application - Webshop Demo Scri ================================================================================== 1. Open ESPM Webshop URL in the browser https://espmxxxxxxxtrial.hanatrial.ondemand.com/espm-cloud-web/webshop/ - ![ESPM1](/docs/demoscript/webshopimages/1.OpenURL.png?raw=true) -2. In the search field, enter “Notebook Basic 15” and press enter key. +2. In the search field, enter “Notebook Basic 15” and press enter key. ![ESPM2](/docs/demoscript/webshopimages/2.NotebookBasic15.png?raw=true) -3. Select “Notebook Basic 15” in the list to view the details of the product. +3. Select “Notebook Basic 15” in the list to view the details of the product. ![ESPM3](/docs/demoscript/webshopimages/3.Notebookbasic15Details.png?raw=true) -4. Click “Add to Cart” button to add the product to the cart. The cart is updated as shown by the icon on the top right corner. +4. Click “Add to Cart” button to add the product to the cart. The cart is updated as shown by the icon on the top right corner. ![ESPM4](/docs/demoscript/webshopimages/4.AddToCart.png?raw=true) -5. Click on the “Cart” icon on the top right corner to view your shopping cart. To checkout, Click on “checkout” button. +5. Click on the “Cart” icon on the top right corner to view your shopping cart. To checkout, Click on “checkout” button. ![ESPM5](/docs/demoscript/webshopimages/5.ViewCart.png?raw=true) -6. In the Checkout screen, Click on Step2 button. +6. In the Checkout screen, Click on Step2 button. ![ESPM6](/docs/demoscript/webshopimages/6.CheckoutScreen1.png?raw=true) -7. Select “I am a new customer” radio button, fill in the customer information and click on “Step3” button. +7. Select “I am a new customer” radio button, fill in the customer information and click on “Step3” button. ![ESPM6](/docs/demoscript/webshopimages/6.CheckoutScreen2.png?raw=true) -8. Enter the Billing information. Click on the Review button. +8. Enter the Billing information. Click on the Review button. ![ESPM6](/docs/demoscript/webshopimages/6.CheckoutScreen3.png?raw=true) -9. In the summary page, Click on “Place an order” button to order the product. +9. In the summary page, Click on “Place an order” button to order the product. ![ESPM6](/docs/demoscript/webshopimages/6.CheckoutScreen4.png?raw=true) -10. The Sales Order is created successfully and a message is shown for the same. +10. The Sales Order is created successfully and a message is shown for the same. ![ESPM6](/docs/demoscript/webshopimages/6.CheckoutScreen5.png?raw=true) diff --git a/docs/documentation/DocumentServiceREADME.md b/docs/documentation/DocumentServiceREADME.md index 7b05408..903f82f 100644 --- a/docs/documentation/DocumentServiceREADME.md +++ b/docs/documentation/DocumentServiceREADME.md @@ -46,22 +46,21 @@ In ESPM Webshop application, we have implemented Document Service of HANA cloud # Demo 1. Click on the “View My Sales Orders” button. - ![ESPM1](/docs/documentation/DocumentServiceImages/ESPM1.jpg?raw=true) -2. Enter the registered email id. +2. Enter the registered email id. ![ESPM2](/docs/documentation/DocumentServiceImages/ESPM2.jpg?raw=true) -3. Click on Get sales orders list, for getting the list of orders. +3. Click on Get sales orders list, for getting the list of orders. ![ESPM3](/docs/documentation/DocumentServiceImages/ESPM3.jpg?raw=true) -4. After clicking on “Get Sales Order List” button, List of invoices come to the list. +4. After clicking on “Get Sales Order List” button, List of invoices come to the list. ![ESPM4](/docs/documentation/DocumentServiceImages/ESPM4.jpg?raw=true) -5. Click on sales order from the list, detail information about customer and product displayed on the right side of the screen. +5. Click on sales order from the list, detail information about customer and product displayed on the right side of the screen. ![ESPM5](/docs/documentation/DocumentServiceImages/ESPM5.jpg?raw=true) -6. Download the pdf by clicking on “Download pdf” icon in the bottom right corner. +6. Download the pdf by clicking on “Download pdf” icon in the bottom right corner. ![ESPM6](/docs/documentation/DocumentServiceImages/ESPM6.jpg?raw=true) @@ -114,7 +113,7 @@ Get access to the root folder of the application document repository. Further fo Folder root = openCmisSession.getRootFolder(); ### Create new folder or file/document as per your requirement -Create sales order as pdf files and export/store pdfs in the document service repository. You can use PDFBox library for creating pdfs. For code, click on the [LINK](/espm-cloud-web/src/main/java/com/sap/espm/model/pdf/generator/InvoicePDFGenerator.java). +Create sales order as pdf files and export/store pdfs in the document service repository. You can use PDFBox library for creating pdfs. For code, click on the [LINK](/espm-cloud-web/src/main/java/com/sap/espm/model/documentservice/InvoiceBuilder.java). ### Use Streaming API’s to download invoices. diff --git a/docs/images/Deployed.png b/docs/images/Deployed.png new file mode 100644 index 0000000..d251acf Binary files /dev/null and b/docs/images/Deployed.png differ diff --git a/docs/images/HCPCockpit.png b/docs/images/HCPCockpit.png new file mode 100644 index 0000000..271f5c6 Binary files /dev/null and b/docs/images/HCPCockpit.png differ diff --git a/docs/images/HCPDeploy.png b/docs/images/HCPDeploy.png new file mode 100644 index 0000000..2ae20e5 Binary files /dev/null and b/docs/images/HCPDeploy.png differ diff --git a/docs/images/RunESPM2.png b/docs/images/RunESPM2.png index 7425492..6e902d2 100644 Binary files a/docs/images/RunESPM2.png and b/docs/images/RunESPM2.png differ diff --git a/docs/images/localuser.png b/docs/images/localuser.png index b98b823..6685db6 100644 Binary files a/docs/images/localuser.png and b/docs/images/localuser.png differ diff --git a/espm-cloud-jpa/pom.xml b/espm-cloud-jpa/pom.xml index de7d042..f352077 100644 --- a/espm-cloud-jpa/pom.xml +++ b/espm-cloud-jpa/pom.xml @@ -15,7 +15,21 @@ org.eclipse.persistence eclipselink - 2.5.1 + + + org.slf4j + slf4j-api + + + + junit + junit + test + + + org.apache.derby + derby + test \ No newline at end of file diff --git a/espm-cloud-jpa/src/main/java/com/sap/espm/model/Customer.java b/espm-cloud-jpa/src/main/java/com/sap/espm/model/Customer.java index 23d93d7..2454f33 100644 --- a/espm-cloud-jpa/src/main/java/com/sap/espm/model/Customer.java +++ b/espm-cloud-jpa/src/main/java/com/sap/espm/model/Customer.java @@ -1,6 +1,8 @@ package com.sap.espm.model; import java.util.Calendar; +import java.util.LinkedHashMap; +import java.util.Map; import javax.persistence.Column; import javax.persistence.Entity; @@ -23,41 +25,34 @@ public class Customer { @Column(name = "CUSTOMER_ID", length = 10) private String customerId; - @SalesOrderReportField @Column(name = "EMAIL_ADDRESS", unique = true) private String emailAddress; @Column(name = "PHONE_NUMBER", length = 30) private String phoneNumber; - - @SalesOrderReportField + @Column(name = "FIRST_NAME", length = 40) private String firstName; - @SalesOrderReportField @Column(name = "LAST_NAME", length = 40) private String lastName; - @SalesOrderReportField @Column(name = "DATE_OF_BIRTH", nullable = false) @Temporal(TemporalType.DATE) private Calendar dateOfBirth; - @SalesOrderReportField @Column(name = "CITY", length = 40) private String city; - @SalesOrderReportField @Column(name = "POSTAL_CODE", length = 10) private String postalCode; - @SalesOrderReportField + @Column(name = "STREET", length = 60) private String street; @Column(name = "HOUSE_NUMBER", length = 10) private String houseNumber; - @SalesOrderReportField @Column(name = "COUNTRY", length = 3) private String country; @@ -148,4 +143,18 @@ public String getCountry() { public void setCountry(String country) { this.country = country; } + + public Map getCustomerReportData() { + + Map customerMapData = new LinkedHashMap(7); + customerMapData.put("firstName", firstName); + customerMapData.put("lastName", lastName); + customerMapData.put("emailAddress", emailAddress); + customerMapData.put("phoneNumber", phoneNumber); + customerMapData.put("city", city); + customerMapData.put("street", street); + customerMapData.put("country", country); + return customerMapData; + + } } \ No newline at end of file diff --git a/espm-cloud-jpa/src/main/java/com/sap/espm/model/CustomerReview.java b/espm-cloud-jpa/src/main/java/com/sap/espm/model/CustomerReview.java index 73b6b6e..555f335 100644 --- a/espm-cloud-jpa/src/main/java/com/sap/espm/model/CustomerReview.java +++ b/espm-cloud-jpa/src/main/java/com/sap/espm/model/CustomerReview.java @@ -7,9 +7,7 @@ import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; -import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; -import javax.persistence.OneToOne; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; diff --git a/espm-cloud-jpa/src/main/java/com/sap/espm/model/Product.java b/espm-cloud-jpa/src/main/java/com/sap/espm/model/Product.java index 3830e03..c54e39b 100644 --- a/espm-cloud-jpa/src/main/java/com/sap/espm/model/Product.java +++ b/espm-cloud-jpa/src/main/java/com/sap/espm/model/Product.java @@ -3,6 +3,7 @@ import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -35,7 +36,6 @@ public class Product { private String name; - @SalesOrderReportField @Column(name = "SHORT_DESCRIPTION") private String shortDescription; @@ -57,7 +57,6 @@ public class Product { @Column(name = "WEIGHT_UNIT", length = 3) private String weightUnit; - @SalesOrderReportField @Column(precision = 23, scale = 3) private BigDecimal price; @@ -84,14 +83,14 @@ public class Product { @OneToOne private Supplier supplier; - - @OneToMany(mappedBy="product",targetEntity=CustomerReview.class,fetch=FetchType.EAGER) - private List reviews; + + @OneToMany(mappedBy = "product", targetEntity = CustomerReview.class, fetch = FetchType.EAGER) + private List reviews; public Product() { this.reviews = new ArrayList(); } - + public String getProductId() { return this.productId; } @@ -235,12 +234,12 @@ public Supplier getSupplier() { public void setSupplier(Supplier param) { this.supplier = param; } - - public void addReview(CustomerReview review){ + + public void addReview(CustomerReview review) { this.reviews.add(review); } - - public List getReviews(){ + + public List getReviews() { return this.reviews; } @@ -255,8 +254,7 @@ private static void updatePrices() { EntityManagerFactory emf = Utility.getEntityManagerFactory(); EntityManager em = emf.createEntityManager(); try { - List products = em.createQuery("SELECT p FROM Product p", - Product.class).getResultList(); + List products = em.createQuery("SELECT p FROM Product p", Product.class).getResultList(); prices = new HashMap(); for (Product p : products) { prices.put(p.getProductId(), p.getPrice()); @@ -326,15 +324,23 @@ private void persist() { } private ProductText getProductText(EntityManager em) { - TypedQuery query = em - .createQuery( - "SELECT p FROM ProductText p WHERE p.productId = :productId AND p.language = :language", - ProductText.class); + TypedQuery query = em.createQuery( + "SELECT p FROM ProductText p WHERE p.productId = :productId AND p.language = :language", + ProductText.class); try { - return query.setParameter("productId", this.getProductId()) - .setParameter("language", "EN").getSingleResult(); + return query.setParameter("productId", this.getProductId()).setParameter("language", "EN") + .getSingleResult(); } catch (NoResultException e) { return null; } } + + public Map getProductReportMap() { + + Map productMap = new LinkedHashMap<>(2); + productMap.put("shortDescription", shortDescription); + productMap.put("price", String.valueOf(price)); + + return productMap; + } } \ No newline at end of file diff --git a/espm-cloud-jpa/src/main/java/com/sap/espm/model/SalesOrderReportField.java b/espm-cloud-jpa/src/main/java/com/sap/espm/model/SalesOrderReportField.java deleted file mode 100644 index 226d8f7..0000000 --- a/espm-cloud-jpa/src/main/java/com/sap/espm/model/SalesOrderReportField.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.sap.espm.model; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -@Target({METHOD, FIELD}) -@Retention(RUNTIME) -public @interface SalesOrderReportField { - - - -} diff --git a/espm-cloud-jpa/src/main/java/com/sap/espm/model/data/DataLoader.java b/espm-cloud-jpa/src/main/java/com/sap/espm/model/data/DataLoader.java index 8f0d9f9..08e92a1 100644 --- a/espm-cloud-jpa/src/main/java/com/sap/espm/model/data/DataLoader.java +++ b/espm-cloud-jpa/src/main/java/com/sap/espm/model/data/DataLoader.java @@ -16,6 +16,7 @@ import com.sap.espm.model.ProductCategory; import com.sap.espm.model.Stock; import com.sap.espm.model.Supplier; +import com.sap.espm.model.util.Utility; /** * Data Loader tool for loading business partners and products into the db. @@ -23,16 +24,37 @@ */ public class DataLoader { + /** + * The {@link Logger} instance used for logging. + */ private static Logger logger = LoggerFactory.getLogger(DataLoader.class); + /** + * The {@link EntityManagerFactory} used for persisting data into the Data + * Source. Refer to the {@link Utility} class for details on how the + * {@link EntityManagerFactory} is configured. + */ private EntityManagerFactory emf; + /** + * The Overloaded constructor of the DataLoader that takes an instance of + * the {@link EntityManagerFactory} instance. + * + * @param emf + */ public DataLoader(EntityManagerFactory emf) { this.emf = emf; } /** - * Load products to db from Products.xml + * This method is used to the parse the contents of the + * "com/sap/espm/model/data/Products.xml" file and populate a list of + * {@link Product} that will eventually be persisted in the Data Source. + * + * @param suppliers + * - The List of {@link Supplier}. + * @return - The list of {@link Product} that will be persisted in the + * Database. */ public List loadProducts(List suppliers) { EntityManager em = emf.createEntityManager(); @@ -40,18 +62,14 @@ public List loadProducts(List suppliers) { List resProd = null; try { em.getTransaction().begin(); - queryProd = em - .createQuery("SELECT p FROM Product p", Product.class); + queryProd = em.createQuery("SELECT p FROM Product p", Product.class); resProd = queryProd.getResultList(); if (resProd.size() > 5) { - logger.info(resProd.size() - + " Products already available in the db"); + logger.info(resProd.size() + " Products already available in the db"); } else { - new XMLParser().readProduct(em, - "com/sap/espm/model/data/Products.xml", suppliers); + new XMLParser().readProduct(em, "com/sap/espm/model/data/Products.xml", suppliers); em.getTransaction().commit(); - queryProd = em.createQuery("SELECT p FROM Product p", - Product.class); + queryProd = em.createQuery("SELECT p FROM Product p", Product.class); resProd = queryProd.getResultList(); logger.info(resProd.size() + " Products loaded into the db"); } @@ -64,7 +82,13 @@ public List loadProducts(List suppliers) { } /** - * Load CustomerReviews to db from CustomerReivews.xml + * This method is used to parse the list of Customer Reviews (pre-populated + * in the "com/sap/espm/model/data/CustomerReviews.xml" file) and return a + * list of {@link CustomerReview}. + * + * @param products + * - The List of {@link Product} + * @return - The list of {@link CustomerReview} */ public List loadCustomerReviews(List products) { EntityManager em = emf.createEntityManager(); @@ -72,18 +96,14 @@ public List loadCustomerReviews(List products) { List resReview = null; try { em.getTransaction().begin(); - queryReviews = em - .createQuery("SELECT p FROM CustomerReview p", CustomerReview.class); + queryReviews = em.createQuery("SELECT p FROM CustomerReview p", CustomerReview.class); resReview = queryReviews.getResultList(); if (resReview.size() > 5) { - logger.info(resReview.size() - + " Customer Reviews already available in the db"); + logger.info(resReview.size() + " Customer Reviews already available in the db"); } else { - new XMLParser().readCustomerReview(em, - "com/sap/espm/model/data/CustomerReviews.xml", products); + new XMLParser().readCustomerReview(em, "com/sap/espm/model/data/CustomerReviews.xml", products); em.getTransaction().commit(); - queryReviews = em.createQuery("SELECT p FROM CustomerReview p", - CustomerReview.class); + queryReviews = em.createQuery("SELECT p FROM CustomerReview p", CustomerReview.class); resReview = queryReviews.getResultList(); logger.info(resReview.size() + " Products loaded into the db"); } @@ -94,9 +114,11 @@ public List loadCustomerReviews(List products) { } return resReview; } - + /** - * Load Customers to db from Business_Partners.xml. + * This method is used to populate the {@link Customer} in the Data Source. + * The list of Business Partners are stored in the + * "com/sap/espm/model/data/Business_Partners.xml" file. */ public void loadCustomers() { EntityManager em = emf.createEntityManager(); @@ -104,18 +126,14 @@ public void loadCustomers() { List resBP; try { em.getTransaction().begin(); - queryBP = em - .createQuery("SELECT c FROM Customer c", Customer.class); + queryBP = em.createQuery("SELECT c FROM Customer c", Customer.class); resBP = queryBP.getResultList(); if (resBP.size() > 5) { - logger.info(resBP.size() - + " Customers already available in the db"); + logger.info(resBP.size() + " Customers already available in the db"); } else { - new XMLParser().readCustomers(em, - "com/sap/espm/model/data/Business_Partners.xml"); + new XMLParser().readCustomers(em, "com/sap/espm/model/data/Business_Partners.xml"); em.getTransaction().commit(); - queryBP = em.createQuery("SELECT c FROM Customer c", - Customer.class); + queryBP = em.createQuery("SELECT c FROM Customer c", Customer.class); resBP = queryBP.getResultList(); logger.info(resBP.size() + " customers loaded into the db"); } @@ -135,18 +153,14 @@ public List loadSuppliers() { List resBP = null; try { em.getTransaction().begin(); - queryBP = em - .createQuery("SELECT s FROM Supplier s", Supplier.class); + queryBP = em.createQuery("SELECT s FROM Supplier s", Supplier.class); resBP = queryBP.getResultList(); if (resBP.size() > 5) { - logger.info(resBP.size() - + " Suppliers already available in the db"); + logger.info(resBP.size() + " Suppliers already available in the db"); } else { - new XMLParser().readSuppliers(em, - "com/sap/espm/model/data/Business_Partners.xml"); + new XMLParser().readSuppliers(em, "com/sap/espm/model/data/Business_Partners.xml"); em.getTransaction().commit(); - queryBP = em.createQuery("SELECT s FROM Supplier s", - Supplier.class); + queryBP = em.createQuery("SELECT s FROM Supplier s", Supplier.class); resBP = queryBP.getResultList(); logger.info(resBP.size() + " suppliers loaded into the db"); } @@ -159,10 +173,12 @@ public List loadSuppliers() { } /** - * Load Product Categories to db from Business_Partners.xml. + * This method is used to populate the Data Source with the list of + * {@link ProductCategory}. This list is defined in the resource file + * "com/sap/espm/model/data/Product_Categories.xml". * * @param products - * TODO + * - The list of the {@link Product}. */ public void loadProductCategories(List products) { EntityManager em = emf.createEntityManager(); @@ -170,22 +186,16 @@ public void loadProductCategories(List products) { List resPC; try { em.getTransaction().begin(); - queryPC = em.createQuery("SELECT pc FROM ProductCategory pc", - ProductCategory.class); + queryPC = em.createQuery("SELECT pc FROM ProductCategory pc", ProductCategory.class); resPC = queryPC.getResultList(); if (resPC.size() > 5) { - logger.info(resPC.size() - + " Product Categories already available in the db"); + logger.info(resPC.size() + " Product Categories already available in the db"); } else { - new XMLParser().readProductCategory(em, - "com/sap/espm/model/data/Product_Categories.xml", - products); + new XMLParser().readProductCategory(em, "com/sap/espm/model/data/Product_Categories.xml", products); em.getTransaction().commit(); - queryPC = em.createQuery("SELECT pc FROM ProductCategory pc", - ProductCategory.class); + queryPC = em.createQuery("SELECT pc FROM ProductCategory pc", ProductCategory.class); resPC = queryPC.getResultList(); - logger.info(resPC.size() - + " Product Categories loaded into the db"); + logger.info(resPC.size() + " Product Categories loaded into the db"); } } catch (Exception e) { logger.error("Exception occured", e); @@ -193,12 +203,13 @@ public void loadProductCategories(List products) { em.close(); } } - + /** - * Load stock into db based on an algorithm + * This method is used to populate the {@link Stock} tables based on the + * list of {@link Product}. * * @param products - * List of products to be added. + * - The list of {@link Product}. */ public void loadStock(List products) { EntityManager em = emf.createEntityManager(); @@ -214,8 +225,7 @@ public void loadStock(List products) { queryStock = em.createQuery("SELECT st FROM Stock st", Stock.class); resStock = queryStock.getResultList(); if (resStock.size() > 5) { - logger.info(resStock.size() - + " Stock already available in the db"); + logger.info(resStock.size() + " Stock already available in the db"); } else { Stock st = null; for (int count = 0; count < products.size(); count++) { @@ -232,15 +242,13 @@ public void loadStock(List products) { st.setQuantity(quantity); st.setMinStock(minStock); st.setLotSize(lotSize); - prod = em.find(Product.class, products.get(count) - .getProductId()); + prod = em.find(Product.class, products.get(count).getProductId()); st.setProduct(prod); em.persist(st); } em.getTransaction().commit(); - queryStock = em.createQuery("SELECT st FROM Stock st", - Stock.class); + queryStock = em.createQuery("SELECT st FROM Stock st", Stock.class); resStock = queryStock.getResultList(); logger.info(resStock.size() + " Stocks loaded into the db"); } @@ -251,10 +259,11 @@ public void loadStock(List products) { } } - -/** - * Load Products, Customers, Suppliers, Product Categories, customer reviews to db from - * respective xml's and Generate Stock. + /** + * This is the entry point method to the class. This method is used to read + * the respective XML present in the resource folder and pre-populate the + * data source with the Product related data. This is a one time operation + * and is done only once when ESPM is loaded for the first time. */ public void loadData() { loadCustomers(); @@ -264,7 +273,6 @@ public void loadData() { loadStock(products); loadProductCategories(products); - } } diff --git a/espm-cloud-jpa/src/main/java/com/sap/espm/model/data/XMLParser.java b/espm-cloud-jpa/src/main/java/com/sap/espm/model/data/XMLParser.java index 215bbea..f02fbf3 100644 --- a/espm-cloud-jpa/src/main/java/com/sap/espm/model/data/XMLParser.java +++ b/espm-cloud-jpa/src/main/java/com/sap/espm/model/data/XMLParser.java @@ -12,6 +12,7 @@ import java.util.Date; import java.util.List; +import javax.persistence.Entity; import javax.persistence.EntityManager; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; @@ -30,7 +31,12 @@ import com.sap.espm.model.Supplier; /** - * Stax Parser Implementation + * Utility class that is used to read the contents of the XMLs present in the + * resource folder and parse the content and construct equivalent POJO classes. + * + * The POJO classes are defined in the package com.sap.espm.model. The POJO + * classes represent {@link Entity} objects that will be persisted into the + * database. * */ public class XMLParser { @@ -127,8 +133,8 @@ public class XMLParser { /** * Parse Product XML and fill it in List * - * @param productXml - * @return Parsed List of Products + * @param productXml - The location of the XML that contains the list of products. + * @return Parsed List of {@link Product} */ public List readProduct(EntityManager em, String productXml, List suppliers) { @@ -324,8 +330,8 @@ public List readProduct(EntityManager em, String productXml, /** * Parse Product XML and fill it in List * - * @param reviewXml - * @return Parsed List of CustomerReviews + * @param reviewXml - The location of the XML that contains the list of Customer Reviews. + * @return Parsed List of {@link CustomerReview} */ public List readCustomerReview(EntityManager em, String reviewXml, List products) { @@ -427,8 +433,8 @@ public List readCustomerReview(EntityManager em, String reviewXm /** * Parse Customers and fill List * - * @param bpXml - * @return Parsed List of Customers + * @param bpXml - The location of the XML that contains the list of {@link Customer} + * @return Parsed List of {@link Customer} */ public List readCustomers(EntityManager em, String bpXml) { ArrayList customers = new ArrayList(); @@ -570,8 +576,8 @@ public List readCustomers(EntityManager em, String bpXml) { /** * Parse Suppliers and fill List * - * @param bpXml - * @return Parsed List of Suppliers + * @param bpXml - The location of the XML that contains the list of Suppliers + * @return Parsed List of {@link Supplier} */ public List readSuppliers(EntityManager em, String bpXml) { ArrayList suppliers = new ArrayList(); @@ -694,13 +700,11 @@ public List readSuppliers(EntityManager em, String bpXml) { } /** - * Parse Product Categeory and fill List - * - * @param pcXml - * @param productList - * TODO + * Parse Product Category and fill List * - * @return Parsed List of Product Categories + * @param pcXml - The location of the XML that contains the list of Product Categories. + * @param productList - The list of {@link Product} + * @return Boolean flag for successful insertion of data. */ public Boolean readProductCategory(EntityManager em, String pcXml, List products) { diff --git a/espm-cloud-jpa/src/main/java/com/sap/espm/model/util/Utility.java b/espm-cloud-jpa/src/main/java/com/sap/espm/model/util/Utility.java index 1f0a634..4deb430 100644 --- a/espm-cloud-jpa/src/main/java/com/sap/espm/model/util/Utility.java +++ b/espm-cloud-jpa/src/main/java/com/sap/espm/model/util/Utility.java @@ -4,13 +4,29 @@ /** * - * Utility class for initializing entity manager factory. + * This is a Singleton Utility class that is used to Configure an + * {@link EntityManagerFactory}. + *

+ * Refer to the Documentation + * (http://docs.oracle.com/javaee/7/api/javax/persistence/EntityManagerFactory.html) + * for more information on how to configure an EntityManager. + *

+ * For more information regarding the Model classes and other JPA related + * configuration details, refer to the "META-INF/persistence.xml" file in the + * resources folder. * */ public class Utility { + /** + * The {@link EntityManagerFactory} instance. + */ private static EntityManagerFactory emf; + /** + * The static method to return the {@link EntityManagerFactory} instance. + * @return + */ public static EntityManagerFactory getEntityManagerFactory() { if (emf == null) { throw new IllegalArgumentException( @@ -19,6 +35,10 @@ public static EntityManagerFactory getEntityManagerFactory() { return emf; } + /** + * Setter for the {@link EntityManagerFactory} + * @param emf - The {@link EntityManagerFactory} to set. + */ public static void setEntityManagerFactory(EntityManagerFactory emf) { Utility.emf = emf; } diff --git a/espm-cloud-web/pom.xml b/espm-cloud-web/pom.xml index 0966e84..9cf7747 100644 --- a/espm-cloud-web/pom.xml +++ b/espm-cloud-web/pom.xml @@ -20,115 +20,83 @@ com.sap.cloud - neo-javaee6-wp-api - ${sap.cloud.sdk.version} + neo-java-web-api provided javax.servlet javax.servlet-api - 3.0.1 compile org.apache.httpcomponents httpclient - 4.3.5 compile org.apache.httpcomponents httpcore - 4.3.2 compile org.slf4j slf4j-api - 1.7.2 compile org.apache.cxf cxf-rt-frontend-jaxrs - 2.7.5 org.slf4j slf4j-log4j12 - 1.7.1 org.apache.olingo olingo-odata2-api - ${olingo.version} compile org.apache.olingo olingo-odata2-core - ${olingo.version} compile org.apache.olingo olingo-odata2-jpa-processor-api - ${olingo.version} compile org.apache.olingo olingo-odata2-api-annotation - ${olingo.version} compile org.apache.olingo olingo-odata2-jpa-processor-core - ${olingo.version} runtime - org.apache.chemistry.opencmis - chemistry-opencmis-commons-impl - 0.13.0 - - - org.apache.chemistry.opencmis - chemistry-opencmis-commons-api - 0.13.0 + org.apache.pdfbox + pdfbox-app + + - org.apache.chemistry.opencmis - chemistry-opencmis-client-api - 0.13.0 + junit + junit + test - org.apache.chemistry.opencmis - chemistry-opencmis-client-impl - 0.13.0 - - - - chemistry-opencmis-client-bindings - - org.apache.chemistry.opencmis - - + org.apache.derby + derby + test - - org.apache.pdfbox - pdfbox-app - 1.8.10 - - - org.codehaus.jettison jettison - 1.3.2 test @@ -137,8 +105,8 @@ ${project.artifactId} + org.apache.maven.plugins maven-clean-plugin - 2.5 @@ -156,7 +124,6 @@ org.apache.maven.plugins maven-dependency-plugin - 2.4 copy-installed @@ -194,148 +161,7 @@ - - com.sap.cloud - neo-javaee6-wp-maven-plugin - ${sap.cloud.sdk.version} - - - - initialize - - - install-sdk - - - - - - ${sap.cloud.sdk.path} - - - - - - local-integration-tests - - false - - local.integration.tests - - - - - - - org.codehaus.mojo - build-helper-maven-plugin - 1.7 - - - reserve-network-port - - reserve-network-port - - validate - - - local.server.console.port - local.server.jmx.port - local.server.http.port - local.server.https.port - local.server.ajp.port - - - - - - - maven-antrun-plugin - 1.7 - - - prepare-local-server - pre-integration-test - - run - - - - - - - - - - - - - - - - - - cleanup-local-server - post-integration-test - - run - - - - - - - - - - - - - maven-failsafe-plugin - 2.14 - - - execute-local-integration-tests - - integration-test - - - ${browser.proxy.settings} - - http://${local.server.host}:${local.server.http.port} - ${webdriver.firefox.bin} - - - - - verify-local-integration-tests - - verify - - - - - - - - - diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/builder/GenericInvoiceBuilder.java b/espm-cloud-web/src/main/java/com/sap/espm/model/builder/GenericInvoiceBuilder.java deleted file mode 100644 index 47383e9..0000000 --- a/espm-cloud-web/src/main/java/com/sap/espm/model/builder/GenericInvoiceBuilder.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.sap.espm.model.builder; - -import java.util.List; -/** - * - */ -public abstract class GenericInvoiceBuilder { - - protected List> reportBuilders; - - public abstract RETURNTYPE generateInvoice(List inputList); - -} diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/builder/ReportBuilder.java b/espm-cloud-web/src/main/java/com/sap/espm/model/builder/ReportBuilder.java deleted file mode 100644 index b6a3e9d..0000000 --- a/espm-cloud-web/src/main/java/com/sap/espm/model/builder/ReportBuilder.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.sap.espm.model.builder; - -import java.util.List; - -public interface ReportBuilder { - - RETURNTYPE generateReportData(List inputList); - -} diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/builder/pdf/CustomerSalesOrderBuilder.java b/espm-cloud-web/src/main/java/com/sap/espm/model/builder/pdf/CustomerSalesOrderBuilder.java deleted file mode 100644 index e81d83a..0000000 --- a/espm-cloud-web/src/main/java/com/sap/espm/model/builder/pdf/CustomerSalesOrderBuilder.java +++ /dev/null @@ -1,52 +0,0 @@ -/** - * - */ -package com.sap.espm.model.builder.pdf; - -import java.util.List; -import java.util.Map; - -import com.sap.espm.model.Customer; -import com.sap.espm.model.SalesOrderHeader; -import com.sap.espm.model.SalesOrderItem; -import com.sap.espm.model.SalesOrderReportField; -import com.sap.espm.model.builder.ReportBuilder; -import com.sap.espm.model.exception.ReportGenerationException; -import com.sap.espm.model.util.ReflectionUtil; - -/** - * - * Function Import processor class for getting customer information - * - */ -public class CustomerSalesOrderBuilder implements ReportBuilder { - - @Override - public StringBuffer generateReportData(List soiList) { - StringBuffer reportData = new StringBuffer(); - if (soiList != null && !soiList.isEmpty()) { - try { - - SalesOrderHeader header = soiList.get(0).getSalesOrderHeader(); - - if (header != null) { - Customer customer = header.getCustomer(); - Map reportMap = ReflectionUtil.generateReportData(customer.getClass(), SalesOrderReportField.class, customer); - reportData.append("Customer Data:"); - reportData.append("|"); - ReflectionUtil.processReportMap(reportMap, reportData); - reportData.append("|"); - - } - } catch (IllegalAccessException illegalAccessException) { - throw new ReportGenerationException("Error Generating the Customer Data for the Sales Order Report"); - } - - } - return reportData; - - } - - - -} diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/builder/pdf/ProductSalesOrderBuilder.java b/espm-cloud-web/src/main/java/com/sap/espm/model/builder/pdf/ProductSalesOrderBuilder.java deleted file mode 100644 index 635ddaf..0000000 --- a/espm-cloud-web/src/main/java/com/sap/espm/model/builder/pdf/ProductSalesOrderBuilder.java +++ /dev/null @@ -1,54 +0,0 @@ -/** - * - */ -package com.sap.espm.model.builder.pdf; - -import java.util.List; -import java.util.Map; - -import javax.persistence.Column; - -import com.sap.espm.model.Product; -import com.sap.espm.model.SalesOrderItem; -import com.sap.espm.model.SalesOrderReportField; -import com.sap.espm.model.builder.ReportBuilder; -import com.sap.espm.model.exception.ReportGenerationException; -import com.sap.espm.model.util.ReflectionUtil; - -/** - * - * Function Import processor class for getting product information - * - */ -public class ProductSalesOrderBuilder implements ReportBuilder { - - @Override - public StringBuffer generateReportData(List soiList) { - StringBuffer reportData=new StringBuffer(); - // get the Product Information from the SalesOrderItem. - if (soiList != null && !soiList.isEmpty()) { - try { - reportData.append("Product Data:"); - reportData.append("|"); - for (SalesOrderItem salesOrderItem : soiList) { - Product product = salesOrderItem.getProduct(); - Map reportMap = ReflectionUtil.generateReportData(product.getClass(), SalesOrderReportField.class, product); - reportData.append("|"); - ReflectionUtil.processReportMap(reportMap, reportData); - reportData.append("Quantity" + " : " + salesOrderItem.getQuantity()); - reportData.append("|"); - } - } catch (IllegalAccessException illegalAccessException) { - throw new ReportGenerationException("Error Generating the Product Data for the Sales Order Report"); - } - - } - return reportData; - } - - private String processProduct(Product product) throws IllegalArgumentException, IllegalAccessException { - return ReflectionUtil.generateEntityData(product, SalesOrderReportField.class); - - } - -} diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/builder/pdf/SalesOrderInvoiceBuilder.java b/espm-cloud-web/src/main/java/com/sap/espm/model/builder/pdf/SalesOrderInvoiceBuilder.java deleted file mode 100644 index 6d1b35b..0000000 --- a/espm-cloud-web/src/main/java/com/sap/espm/model/builder/pdf/SalesOrderInvoiceBuilder.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.sap.espm.model.builder.pdf; - -import java.util.List; - -import com.sap.espm.model.SalesOrderItem; -import com.sap.espm.model.builder.GenericInvoiceBuilder; -import com.sap.espm.model.builder.ReportBuilder; -/** - * - * Function Import processor class for building Sales Order Invoice - * - */ -public class SalesOrderInvoiceBuilder extends - GenericInvoiceBuilder { - - public SalesOrderInvoiceBuilder( - List> builderList) { - this.reportBuilders = builderList; - } - - @Override - public StringBuffer generateInvoice(List inputList) { - StringBuffer reportBuffer = new StringBuffer(); - if (inputList != null && !inputList.isEmpty() && reportBuilders != null - && !reportBuilders.isEmpty()) { - for (ReportBuilder reportBuilder : reportBuilders) { - reportBuffer - .append(reportBuilder.generateReportData(inputList)); - reportBuffer.append("|"); - - } - } - return reportBuffer; - } - -} diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/documentservice/CMISSessionHelper.java b/espm-cloud-web/src/main/java/com/sap/espm/model/documentservice/CMISSessionHelper.java new file mode 100644 index 0000000..bc97594 --- /dev/null +++ b/espm-cloud-web/src/main/java/com/sap/espm/model/documentservice/CMISSessionHelper.java @@ -0,0 +1,122 @@ +package com.sap.espm.model.documentservice; + +import javax.naming.InitialContext; +import javax.naming.NamingException; + +import org.apache.chemistry.opencmis.client.api.Session; +import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sap.ecm.api.EcmService; +import com.sap.ecm.api.RepositoryOptions; +import com.sap.ecm.api.RepositoryOptions.Visibility; +import com.sap.ecm.api.ServiceException; +import com.sap.espm.model.exception.CMISConnectionException; +import com.sap.espm.model.util.ReadProperties; + +/** + * This class is used to instantiate a {@link Session} that will be used to + * connect to the document repository. Using this {@link Session} object we can + * retrieve and store documents in the document storage. + * + */ +public final class CMISSessionHelper { + + /** + * The {@link Logger} instance used for logging. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(CMISSessionHelper.class); + + /** + * The {@link CMISSessionHelper} used for the Singleton. + */ + private static CMISSessionHelper helper; + + /** + * The static instance of the {@link Session} that will be used to connect + * and retrieve data from the Document repository. + */ + private static Session openCmisSession = null; + + /** + * Double checked locking for init of the {@link CMISSessionHelper}. + * + * @return - The single instance of the {@link CMISSessionHelper}. + */ + public static CMISSessionHelper getInstance() { + if (helper == null) { + synchronized (CMISSessionHelper.class) { + if (helper == null) { + helper = new CMISSessionHelper(); + } + } + } + return helper; + } + + /** + * Public Constructor. This constructor will use the credentials to connect + * to the Document storage (located in the "config.properties" file in the + * resources folder). Once the connection is established, a check is + * performed to check whether the document repository exists or not, if it + * does not, a new document repository is created. This document repository + * is used to connect to store and retrieve the documents used in ESPM. + */ + private CMISSessionHelper() { + + String repositoryUniqueName = ""; + String repositorySecretKey = ""; + EcmService ecmSvc = null; + try { + + InitialContext ctx = new InitialContext(); + String lookupName = "java:comp/env/" + "EcmService"; + ecmSvc = (EcmService) ctx.lookup(lookupName); + repositoryUniqueName = ReadProperties.getInstance().getValue("uniqueName"); + repositorySecretKey = ReadProperties.getInstance().getValue("secretKey"); + openCmisSession = ecmSvc.connect(repositoryUniqueName, repositorySecretKey); + + } catch (NamingException | ExceptionInInitializerError namingException) { + LOGGER.error(namingException.getMessage()); + throw new CMISConnectionException(namingException); + } catch (ServiceException serviceException) { + LOGGER.error(serviceException.getMessage()); + throw new CMISConnectionException(serviceException); + } catch (CmisObjectNotFoundException e) { + // Check if the repository exists, else create + /* + * This catch block will always be executed the first time as the + * repository folder may not exists. + */ + RepositoryOptions options = new RepositoryOptions(); + options.setUniqueName(repositoryUniqueName); + options.setRepositoryKey(repositorySecretKey); + options.setVisibility(Visibility.PROTECTED); + ecmSvc.createRepository(options); + // should be created now, so connect to it + openCmisSession = ecmSvc.connect(repositoryUniqueName, repositorySecretKey); + } catch (Exception exception) { + // Generic Exception Block, in the case of exception while + // connection to a local Document Store. + LOGGER.error(exception.getMessage()); + throw new CMISConnectionException(exception); + } + } + + /** + * This method is used to return the {@link Session} used to connect to the + * document repository. If connection to the document repository was not + * possible, then a null object is returned. + * + * @return + */ + public Session getSession() { + /* + * if (helper == null) { helper = new CMISSessionHelper(); } + */ + + return openCmisSession; + } + +} diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/documentservice/InvoiceBuilder.java b/espm-cloud-web/src/main/java/com/sap/espm/model/documentservice/InvoiceBuilder.java new file mode 100644 index 0000000..6bd1f86 --- /dev/null +++ b/espm-cloud-web/src/main/java/com/sap/espm/model/documentservice/InvoiceBuilder.java @@ -0,0 +1,153 @@ +package com.sap.espm.model.documentservice; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.chemistry.opencmis.client.api.Document; +import org.apache.chemistry.opencmis.client.api.Folder; +import org.apache.chemistry.opencmis.commons.PropertyIds; +import org.apache.chemistry.opencmis.commons.data.ContentStream; +import org.apache.chemistry.opencmis.commons.enums.VersioningState; +import org.apache.pdfbox.exceptions.COSVisitorException; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.edit.PDPageContentStream; +import org.apache.pdfbox.pdmodel.font.PDFont; +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.sap.espm.model.SalesOrderHeader; +import com.sap.espm.model.SalesOrderItem; +import com.sap.espm.model.exception.CMISConnectionException; +import com.sap.espm.model.exception.ReportGenerationException; + +/** + * This class is used to generate an Invoice based on a Customer's Order(s). The + * Order related information are obtained via a {@link SalesOrderItem} object. + * + */ +public class InvoiceBuilder { + + /** + * The {@link Logger} instance used for logging. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(InvoiceBuilder.class); + + /** + * This method will be used to generate a sales order based on the input + * {@link SalesOrderItem} entity object passed as input. + *

+ * Based on the input {@link SalesOrderItem}, the Customer details are + * obtained from the {@link SalesOrderHeader} and the product details of the + * order are obtained from the {@link SalesOrderItem}. + *

+ * Using the above mentioned data, the content is populated in a + * {@link PDPageContentStream} object. This {@link PDPageContentStream} is + * then added to a {@link PDDocument}. This {@link PDDocument} represents + * the PDF document that will be stored in the document repository. + * + * @param salesOrderItemList + * - The input list of {@link SalesOrderItem}. + * @return - if the document generation and upload is successful, this + * string variable will hold the location of the document on the + * document storage. + */ + public String generateInvoice(List salesOrderItemList) { + + Map customerMap = null; + String reportPath = null; + + /* + * Flow/Algo; 1) Get the Customer Map from the SalesOrderHeader (fetched + * from SalesOrderHeader) 2) Get the Product Map from the SalesOrderItem + * 3) Add the Map data in the PDF Stream. + */ + + if (salesOrderItemList != null && salesOrderItemList.size() >= 1) { + + try { + + // Create the PDF document content + // access the root folder of the repository + Folder root = CMISSessionHelper.getInstance().getSession().getRootFolder(); + PDDocument invoiceDocument = new PDDocument(); + PDPage page = new PDPage(); + invoiceDocument.addPage(page); + PDPageContentStream contentStream = null; + + contentStream = new PDPageContentStream(invoiceDocument, page); + contentStream.beginText(); + + PDFont font = PDType1Font.TIMES_ROMAN; + contentStream.setFont(font, 10); + contentStream.moveTextPositionByAmount(100, 500); + + // 1. Get the Customer Map Details. + customerMap = salesOrderItemList.get(0).getSalesOrderHeader().getCustomer().getCustomerReportData(); + + for (Entry entry : customerMap.entrySet()) { + String customerField = entry.getKey(); + String customerValue = entry.getValue(); + contentStream.drawString(customerField + " : " + customerValue); + contentStream.moveTextPositionByAmount(0, 10); + + } + + // 2. Generate the Sales Order Data. + + for (SalesOrderItem salesOrderItem : salesOrderItemList) { + Map productMap = salesOrderItem.getProduct().getProductReportMap(); + + // 3. Write each map details in the Stream. + for (Entry product : productMap.entrySet()) { + String productField = product.getKey(); + String productValue = product.getValue(); + + contentStream.drawString(productField + " : " + productValue); + contentStream.moveTextPositionByAmount(0, 10); + + } + + } + + // 4. Close the stream + contentStream.endText(); + contentStream.close(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + invoiceDocument.save(out); + invoiceDocument.close(); + + Map properties = new HashMap(); + properties.put(PropertyIds.OBJECT_TYPE_ID, "cmis:document"); + + // PDF file name + String fileName = "Invoice" + salesOrderItemList.get(0).getSalesOrderId() + System.currentTimeMillis() + + ".pdf"; + properties.put(PropertyIds.NAME, fileName); + byte[] encoded = out.toByteArray(); + InputStream inputStream = new ByteArrayInputStream(encoded); + ContentStream contentStream1 = CMISSessionHelper.getInstance().getSession().getObjectFactory() + .createContentStream(fileName, -1, "application/pdf;charset=UTF-8", inputStream); + + Document cmisDocument = root.createDocument(properties, contentStream1, VersioningState.NONE); + inputStream.close(); + out.close(); + reportPath = cmisDocument.getId(); + + } catch (IOException | COSVisitorException | CMISConnectionException e) { + LOGGER.error(e.getMessage()); + throw new ReportGenerationException(e); + } + + } + return reportPath; + } + +} diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/exception/BaseESPMRunTimeException.java b/espm-cloud-web/src/main/java/com/sap/espm/model/exception/BaseESPMRunTimeException.java index af51b1c..aaac7a9 100644 --- a/espm-cloud-web/src/main/java/com/sap/espm/model/exception/BaseESPMRunTimeException.java +++ b/espm-cloud-web/src/main/java/com/sap/espm/model/exception/BaseESPMRunTimeException.java @@ -4,18 +4,35 @@ package com.sap.espm.model.exception; /** - * Global Exception handler + * This global exception extends the {@link RuntimeException}. It will be used + * as the parent class for defining {@link RuntimeException} in the application. * */ public class BaseESPMRunTimeException extends RuntimeException { + /** + * Serial Id + */ + private static final long serialVersionUID = 1L; + + /** + * Constructor taking the error message. + * + * @param errorMessage + * - The error message. + */ public BaseESPMRunTimeException(String errorMessage) { super(errorMessage); } /** + * The constructor taking the {@link Throwable} instance. * + * @param throwable + * - The {@link Throwable} instance to wrap. */ - private static final long serialVersionUID = 1L; + public BaseESPMRunTimeException(Throwable throwable) { + super(throwable); + } } diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/exception/CMISConnectionException.java b/espm-cloud-web/src/main/java/com/sap/espm/model/exception/CMISConnectionException.java new file mode 100644 index 0000000..7275b2b --- /dev/null +++ b/espm-cloud-web/src/main/java/com/sap/espm/model/exception/CMISConnectionException.java @@ -0,0 +1,35 @@ +package com.sap.espm.model.exception; + +/** + * This class is used as a wrapper for exceptions while connecting to the + * Document Storage via the CMIS library. + */ +public class CMISConnectionException extends BaseESPMRunTimeException { + + /** + * Serial Id. + */ + private static final long serialVersionUID = 1L; + + /** + * Constructor taking error message as input parameter. + * + * @param errorMessage + * - The error message. + */ + public CMISConnectionException(String errorMessage) { + super(errorMessage); + + } + + /** + * Constructor taking a {@link Throwable} as input parameter + * + * @param throwable + * - The {@link Throwable} to wrap. + */ + public CMISConnectionException(Throwable throwable) { + super(throwable); + } + +} diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/exception/ReportGenerationException.java b/espm-cloud-web/src/main/java/com/sap/espm/model/exception/ReportGenerationException.java index 1d69bb0..18cdc46 100644 --- a/espm-cloud-web/src/main/java/com/sap/espm/model/exception/ReportGenerationException.java +++ b/espm-cloud-web/src/main/java/com/sap/espm/model/exception/ReportGenerationException.java @@ -4,15 +4,35 @@ package com.sap.espm.model.exception; /** - * Global Exception handler + * This Exception will be used for any error scenarios while generating a + * customer sales order. * */ public class ReportGenerationException extends BaseESPMRunTimeException { + /** + * Serial Id. + */ + private static final long serialVersionUID = 4501161376995698587L; + + /** + * Constructor taking error message as input parameter. + * + * @param errorMessage + * - The error message. + */ public ReportGenerationException(String errorMessage) { super(errorMessage); } - private static final long serialVersionUID = 4501161376995698587L; + /** + * Constructor taking a {@link Throwable} as input parameter + * + * @param throwable + * - The {@link Throwable} to wrap. + */ + public ReportGenerationException(Throwable throwable) { + super(throwable); + } } diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/function/impl/CustomerProcessor.java b/espm-cloud-web/src/main/java/com/sap/espm/model/function/impl/CustomerProcessor.java index 865975e..cbcb802 100644 --- a/espm-cloud-web/src/main/java/com/sap/espm/model/function/impl/CustomerProcessor.java +++ b/espm-cloud-web/src/main/java/com/sap/espm/model/function/impl/CustomerProcessor.java @@ -21,7 +21,17 @@ /** * - * Function Import processor class for Customer + * This is a custom Apache Olingo Function Import. For more reference + * information regarding a Function Import, refer to the official Olingo + * documentation: + *

+ * https://olingo.apache.org/doc/odata2/tutorials/jpafunctionimport.html + *

+ * http://olingo.apache.org/doc/odata2/ + *

+ * This class is used to define custom OData + * functions for {@link Customer} entity. + * * */ public class CustomerProcessor { @@ -57,7 +67,7 @@ public List getCustomerByEmailAddress( throw new ODataApplicationException( "No matching customer with Email Address:" + emailAddress, Locale.ENGLISH, - HttpStatusCodes.BAD_REQUEST); + HttpStatusCodes.BAD_REQUEST, e); } } finally { em.close(); diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/function/impl/CustomerReviewProcessor.java b/espm-cloud-web/src/main/java/com/sap/espm/model/function/impl/CustomerReviewProcessor.java index b04cb80..1fdf765 100644 --- a/espm-cloud-web/src/main/java/com/sap/espm/model/function/impl/CustomerReviewProcessor.java +++ b/espm-cloud-web/src/main/java/com/sap/espm/model/function/impl/CustomerReviewProcessor.java @@ -21,6 +21,19 @@ import com.sap.espm.model.Product; import com.sap.espm.model.util.Utility; +/** + * This is a custom Apache Olingo Function Import. For more reference + * information regarding a Function Import, refer to the official Olingo + * documentation: + *

+ * https://olingo.apache.org/doc/odata2/tutorials/jpafunctionimport.html + *

+ * http://olingo.apache.org/doc/odata2/ + *

+ * This class is used as a function import to define custom OData functions + * regarding {@link CustomerReview} entity model. + * + */ public class CustomerReviewProcessor { /** @@ -67,7 +80,7 @@ public CustomerReview createCustomerReview( } catch (NoResultException e) { throw new ODataApplicationException( "Error creating customer review:" , Locale.ENGLISH, - HttpStatusCodes.BAD_REQUEST); + HttpStatusCodes.BAD_REQUEST, e); } } finally { em.close(); diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/function/impl/SalesOrderProcessor.java b/espm-cloud-web/src/main/java/com/sap/espm/model/function/impl/SalesOrderProcessor.java index 111e534..3c100e2 100644 --- a/espm-cloud-web/src/main/java/com/sap/espm/model/function/impl/SalesOrderProcessor.java +++ b/espm-cloud-web/src/main/java/com/sap/espm/model/function/impl/SalesOrderProcessor.java @@ -1,7 +1,6 @@ package com.sap.espm.model.function.impl; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Locale; @@ -18,20 +17,34 @@ import org.apache.olingo.odata2.api.commons.HttpStatusCodes; import org.apache.olingo.odata2.api.exception.ODataApplicationException; import org.apache.olingo.odata2.api.exception.ODataException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.sap.espm.model.Customer; import com.sap.espm.model.Product; import com.sap.espm.model.SalesOrderHeader; import com.sap.espm.model.SalesOrderItem; -import com.sap.espm.model.pdf.generator.InvoicePDFGenerator; +import com.sap.espm.model.documentservice.CMISSessionHelper; +import com.sap.espm.model.documentservice.InvoiceBuilder; +import com.sap.espm.model.exception.CMISConnectionException; +import com.sap.espm.model.exception.ReportGenerationException; import com.sap.espm.model.util.Utility; /** - * - * Function Import processor class for Sales Orders - * + * * This is a custom Apache Olingo Function Import. For more reference + * information regarding a Function Import, refer to the official Olingo + * documentation: + *

+ * https://olingo.apache.org/doc/odata2/tutorials/jpafunctionimport.html + *

+ * http://olingo.apache.org/doc/odata2/ + *

+ * This class is used to define custom {@link SalesOrderItem} entity Odata functions. + * */ public class SalesOrderProcessor { + + private static final Logger LOGGER = LoggerFactory.getLogger(SalesOrderProcessor.class); /** * Function Import implementation for confirming a sales order @@ -44,18 +57,14 @@ public class SalesOrderProcessor { @SuppressWarnings("unchecked") @EdmFunctionImport(name = "ConfirmSalesOrder", entitySet = "SalesOrderHeaders", returnType = @ReturnType(type = Type.ENTITY, isCollection = true)) public List confirmSalesOrder( - @EdmFunctionImportParameter(name = "SalesOrderId") String salesOrderId) - throws ODataException { + @EdmFunctionImportParameter(name = "SalesOrderId") String salesOrderId) throws ODataException { EntityManagerFactory emf = Utility.getEntityManagerFactory(); EntityManager em = emf.createEntityManager(); try { - Query query = em - .createQuery("SELECT s FROM SalesOrderHeader s WHERE s.salesOrderId =" - + salesOrderId); + Query query = em.createQuery("SELECT s FROM SalesOrderHeader s WHERE s.salesOrderId =" + salesOrderId); try { - SalesOrderHeader so = (SalesOrderHeader) query - .getSingleResult(); + SalesOrderHeader so = (SalesOrderHeader) query.getSingleResult(); em.getTransaction().begin(); so.setLifeCycleStatus("P"); so.setLifeCycleStatusName("In Process"); @@ -63,16 +72,13 @@ public List confirmSalesOrder( em.getTransaction().commit(); List salesorderlist = null; - query = em - .createQuery("SELECT s FROM SalesOrderHeader s WHERE s.salesOrderId ='" - + salesOrderId + "'"); + query = em.createQuery("SELECT s FROM SalesOrderHeader s WHERE s.salesOrderId ='" + salesOrderId + "'"); salesorderlist = query.getResultList(); return salesorderlist; } catch (NoResultException e) { - throw new ODataApplicationException( - "No Sales Order with Sales Order Id:" + salesOrderId, - Locale.ENGLISH, HttpStatusCodes.BAD_REQUEST); + throw new ODataApplicationException("No Sales Order with Sales Order Id:" + salesOrderId, + Locale.ENGLISH, HttpStatusCodes.BAD_REQUEST, e); } } finally { em.close(); @@ -90,33 +96,26 @@ public List confirmSalesOrder( @SuppressWarnings("unchecked") @EdmFunctionImport(name = "CancelSalesOrder", entitySet = "SalesOrderHeaders", returnType = @ReturnType(type = Type.ENTITY, isCollection = true)) public List cancelSalesOrder( - @EdmFunctionImportParameter(name = "SalesOrderId") String salesOrderId) - throws ODataException { + @EdmFunctionImportParameter(name = "SalesOrderId") String salesOrderId) throws ODataException { EntityManagerFactory emf = Utility.getEntityManagerFactory(); EntityManager em = emf.createEntityManager(); try { - Query query = em - .createQuery("SELECT s FROM SalesOrderHeader s WHERE s.salesOrderId =" - + salesOrderId); + Query query = em.createQuery("SELECT s FROM SalesOrderHeader s WHERE s.salesOrderId =" + salesOrderId); try { - SalesOrderHeader so = (SalesOrderHeader) query - .getSingleResult(); + SalesOrderHeader so = (SalesOrderHeader) query.getSingleResult(); em.getTransaction().begin(); so.setLifeCycleStatus("X"); so.setLifeCycleStatusName("Cancelled"); em.persist(so); em.getTransaction().commit(); List salesOrderList = null; - query = em - .createQuery("SELECT s FROM SalesOrderHeader s WHERE s.salesOrderId ='" - + salesOrderId + "'"); + query = em.createQuery("SELECT s FROM SalesOrderHeader s WHERE s.salesOrderId ='" + salesOrderId + "'"); salesOrderList = query.getResultList(); return salesOrderList; } catch (NoResultException e) { - throw new ODataApplicationException( - "No Sales Order with Sales Order Id:" + salesOrderId, - Locale.ENGLISH, HttpStatusCodes.BAD_REQUEST); + throw new ODataApplicationException("No Sales Order with Sales Order Id:" + salesOrderId, + Locale.ENGLISH, HttpStatusCodes.BAD_REQUEST , e); } } finally { em.close(); @@ -135,61 +134,65 @@ public List cancelSalesOrder( @SuppressWarnings("unchecked") @EdmFunctionImport(name = "GetSalesOrderItemsById", entitySet = "SalesOrderItems", returnType = @ReturnType(type = Type.ENTITY, isCollection = true)) public List getSalesOrderById( - @EdmFunctionImportParameter(name = "SalesOrderId") String salesOrderId) - throws ODataException { + @EdmFunctionImportParameter(name = "SalesOrderId") String salesOrderId) throws ODataException { EntityManagerFactory emf = Utility.getEntityManagerFactory(); EntityManager em = emf.createEntityManager(); List soiList = null; try { - - Query query = em.createQuery("SELECT soi FROM SalesOrderItem soi where soi.id.salesOrderId='"+ salesOrderId +"'"); - + Query query = em.createQuery("SELECT soi FROM SalesOrderItem soi where soi.id.salesOrderId= :salesOrderId"); + query.setParameter("salesOrderId", salesOrderId); + try { soiList = query.getResultList(); - if(soiList!=null && soiList.size()>=1){ - query = em.createQuery("SELECT soh FROM SalesOrderHeader soh where soh.salesOrderId='"+ salesOrderId +"'"); - List salesOrderHeaderList = query.getResultList(); - - for(SalesOrderHeader salesOrderHeader : salesOrderHeaderList){ - List salesOrderItemList = salesOrderHeader.getSalesOrderItems(); - for(SalesOrderItem salesOrderItem : salesOrderItemList){ - query = em.createQuery("SELECT product FROM Product product where product.productId = :productId"); - query.setParameter("productId", salesOrderItem.getProductId()); - Product product = (Product) query.getSingleResult(); - salesOrderItem.setProduct(product); - + if (soiList != null && soiList.size() >= 1) { + + for (SalesOrderItem salesOrderItem : soiList) { + query = em.createQuery( + "SELECT product FROM Product product where product.productId = :productId"); + query.setParameter("productId", salesOrderItem.getProductId()); + Product product = (Product) query.getSingleResult(); + salesOrderItem.setProduct(product); + + } + // if the sales order are fetched successfully, generate the + // pdf report data. + try { + if (CMISSessionHelper.getInstance().getSession() != null) { + InvoiceBuilder builder = new InvoiceBuilder(); + String reportPath = builder.generateInvoice(soiList); + updateSalesOrderHeader(reportPath, soiList, em); } - + } catch (CMISConnectionException cmisConnectionException) { + // There was an exception while generating the report. + LOGGER.error(cmisConnectionException.getMessage()); } - // if the sales order are fetched successfully, generate the pdf report data. - InvoicePDFGenerator generator = new InvoicePDFGenerator(); - String reportPath = generator.generateInvoicePdf(soiList); - updateSalesOrderHeader(reportPath, soiList, em); + + } } catch (NoResultException e) { - throw new ODataApplicationException( - "No matching Sales Order with Sales Order Id:" - + salesOrderId, Locale.ENGLISH, - HttpStatusCodes.BAD_REQUEST); - } catch(Exception exception){ - exception.printStackTrace(); - } catch(Throwable throwable){ - throwable.printStackTrace(); + throw new ODataApplicationException("No matching Sales Order with Sales Order Id:" + salesOrderId, + Locale.ENGLISH, HttpStatusCodes.BAD_REQUEST, e); + } catch (ReportGenerationException reportGenerationException) { + //LOGGER.error("Exception while generating the report : " + reportGenerationException.getMessage()); + reportGenerationException.printStackTrace(); + throw new ODataApplicationException("PDF Report Generation Error for :" + salesOrderId, + Locale.ENGLISH, HttpStatusCodes.INTERNAL_SERVER_ERROR, reportGenerationException); } + return soiList; } finally { em.close(); } } + /** - * Function Import implementation for updating SalesOrderHeader + * Function Import implementation for updating SalesOrderHeader */ - private void updateSalesOrderHeader(String reportPath, - List soiList, EntityManager em) { + private void updateSalesOrderHeader(String reportPath, List soiList, EntityManager em) { if (soiList != null && !soiList.isEmpty()) { EntityTransaction transaction = em.getTransaction(); try { @@ -201,37 +204,40 @@ private void updateSalesOrderHeader(String reportPath, orderItem.getSalesOrderHeader().setInvoiceLink(reportPath); // save the soiList. em.merge(orderItem); - + } - transaction.commit(); - } finally { + } finally { + if(transaction!=null){ + transaction.commit(); + } + } } } - + /** - * Function Import implementation for getting all the Sales Order invoices by email Address - * under a Sales Order Header + * Function Import implementation for getting all the Sales Order invoices + * by email Address under a Sales Order Header * * @param emailAddreaa - * + * * @return SalesOrderHeader entity. * @throws ODataException */ @SuppressWarnings("unchecked") @EdmFunctionImport(name = "GetSalesOrderInvoiceByEmail", entitySet = "SalesOrderHeaders", returnType = @ReturnType(type = Type.ENTITY, isCollection = true)) public List getSalesOrderInvoiceByEmail( - @EdmFunctionImportParameter(name = "EmailAddress") String emailAddress) - throws ODataException { + @EdmFunctionImportParameter(name = "EmailAddress") String emailAddress) throws ODataException { EntityManagerFactory emf = Utility.getEntityManagerFactory(); EntityManager em = emf.createEntityManager(); List orderList = new ArrayList<>(); List salesOrderHeaderList = new ArrayList<>(); List itemList = new ArrayList<>(); - try { - Query querySOItems; ; + try { + Query querySOItems; + ; Query queryCustomer = em.createQuery("SELECT c FROM Customer c where c.emailAddress= :emailAddress"); queryCustomer.setParameter("emailAddress", emailAddress); Customer c = (Customer) queryCustomer.getSingleResult(); @@ -240,7 +246,7 @@ public List getSalesOrderInvoiceByEmail( .createQuery("SELECT soh FROM SalesOrderHeader soh where soh.customerId= :customerId"); querySOHeader.setParameter("customerId", customerId); orderList = querySOHeader.getResultList(); - for( SalesOrderHeader salesOrderHeader : orderList){ + for (SalesOrderHeader salesOrderHeader : orderList) { querySOItems = em .createQuery("SELECT soi FROM SalesOrderItem soi where soi.id.salesOrderId= :salesOrderId"); querySOItems.setParameter("salesOrderId", salesOrderHeader.getSalesOrderId()); @@ -248,32 +254,21 @@ public List getSalesOrderInvoiceByEmail( salesOrderHeader.setSalesOrderItems(itemList); salesOrderHeader.setCustomer(c); salesOrderHeaderList.add(salesOrderHeader); - + } - - - + } catch (NoResultException e) { - throw new ODataApplicationException( - "No Sales Order Invoices with emailId Id:......." + emailAddress, - Locale.ENGLISH, HttpStatusCodes.BAD_REQUEST); + throw new ODataApplicationException("No Sales Order Invoices with emailId Id:......." + emailAddress, + Locale.ENGLISH, HttpStatusCodes.BAD_REQUEST, e); } catch (Exception exception) { - throw new ODataApplicationException( - "No Sales Order Invoices with emailId Id:" + emailAddress, - Locale.ENGLISH, HttpStatusCodes.BAD_REQUEST); - } catch (Throwable throwable){ - //TODO: remove this - throwable.printStackTrace(); - } - - finally { + throw new ODataApplicationException("No Sales Order Invoices with emailId Id:" + emailAddress, + Locale.ENGLISH, HttpStatusCodes.BAD_REQUEST, exception); + } finally { em.close(); } return salesOrderHeaderList; } - } - diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/pdf/generator/CmisRead.java b/espm-cloud-web/src/main/java/com/sap/espm/model/pdf/generator/CmisRead.java index 797e3d2..ce46066 100644 --- a/espm-cloud-web/src/main/java/com/sap/espm/model/pdf/generator/CmisRead.java +++ b/espm-cloud-web/src/main/java/com/sap/espm/model/pdf/generator/CmisRead.java @@ -3,8 +3,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import javax.naming.InitialContext; -import javax.naming.NamingException; + import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -14,63 +13,119 @@ import org.apache.chemistry.opencmis.client.api.Document; import org.apache.chemistry.opencmis.client.api.Session; import org.apache.chemistry.opencmis.commons.data.ContentStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import com.sap.ecm.api.EcmService; -import com.sap.espm.model.util.ReadProperties; +import com.sap.espm.model.documentservice.CMISSessionHelper; +/** + * This {@link HttpServlet} is used to download the Sales Order report for the + * customer based on his/her sales order history. + *

+ * For this {@link HttpServlet}, the init() method is used to fetch the + * {@link Session} object that will be used to connect and download documents + * from the document repository. The {@link Session} object is instantiated only + * once via the {@link CMISSessionHelper} class. + * + */ public class CmisRead extends HttpServlet { + /** + * {@link Logger} implementation. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(CmisRead.class); + + /** + * Serial Id. + */ private static final long serialVersionUID = 1L; - - public CmisRead() { - super(); - } - InitialContext ctx; - EcmService ecmSvc=null; - Session openCmisSession=null; - String repositoryUniqueName=""; - String repositorySecretKey=""; - - public void init(ServletConfig config) throws ServletException { - super.init(config); - - try { - ctx = new InitialContext(); - String lookupName = "java:comp/env/" + "EcmService"; - ecmSvc = (EcmService) ctx.lookup(lookupName); - repositoryUniqueName = ReadProperties.getInstance().getValue("uniqueName"); - repositorySecretKey=ReadProperties.getInstance().getValue("secretKey"); - openCmisSession= ecmSvc.connect(repositoryUniqueName, repositorySecretKey); - - } catch (NamingException e1) { - e1.printStackTrace(); + + /** + * Public default constructor. + */ + public CmisRead() { + super(); } - } - - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - final String objectId = request.getParameter("objectId"); + + /** + * The {@link Session} used to connect to the document storage. + */ + private Session openCmisSession; + + /** + * This init method is used to initialize the connection of the + * {@link Session}. This is done via the {@link CMISSessionHelper} class. + */ + public void init(ServletConfig config) throws ServletException { + super.init(config); + try { - Document doc = (Document) openCmisSession.getObject(objectId); - ContentStream content = doc.getContentStream(); - String type = content.getMimeType(); - String name = content.getFileName(); - int length = (int) content.getLength(); - InputStream stream = content.getStream(); - response.setContentType(type); - response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + name); - response.setContentLength(length); - ioCopy(stream, response.getOutputStream()); - } catch(Exception exception){ - exception.printStackTrace(); + openCmisSession = CMISSessionHelper.getInstance().getSession(); + + } catch (Exception | NoClassDefFoundError e1) { + /* + * We are catching NoClassDefFoundError as when we deploy on local + * Servlet containers, Instantiation of the Session object for CMIS + * fails. + */ + LOGGER.error(e1.getMessage()); } - catch(Throwable throwable){ - throwable.printStackTrace(); + } + + /** + * This is a custom implementation of the doGet method of the + * {@link HttpServlet}. + *

+ * Here, we expect an "objectId" to be passed as input parameter. This + * objectId will be fetched to the {@link Session} to fetch the existing + * document(if present). + */ + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + final String objectId = request.getParameter("objectId"); + try { + if (openCmisSession != null) { + Document doc = (Document) openCmisSession.getObject(objectId); + ContentStream content = doc.getContentStream(); + String type = content.getMimeType(); + String name = content.getFileName(); + int length = (int) content.getLength(); + InputStream stream = content.getStream(); + response.setContentType(type); + response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + name); + response.setContentLength(length); + ioCopy(stream, response.getOutputStream()); + } else { + response.setStatus(501); + } + + } catch (Exception exception) { + exception.printStackTrace(); } - + } - protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + /** + * Here we mainly call the doGet() method. No custom implementation. + */ + protected void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { doGet(request, response); } + + /** + * Copy the contents of the stream returned from the Document Storage to the + * HTTP output stream. + * + * @param in + * - The input stream from the Document Storage returned via + * CMIS. + * @param out + * - The HTTP Output stream. + * @throws IOException + * - The {@link IOException} in case of any exception while + * processing the streams. + */ private void ioCopy(InputStream in, OutputStream out) throws IOException { byte[] buf = new byte[1 << 13]; int read; diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/pdf/generator/InvoicePDFGenerator.java b/espm-cloud-web/src/main/java/com/sap/espm/model/pdf/generator/InvoicePDFGenerator.java deleted file mode 100644 index 06a5cc7..0000000 --- a/espm-cloud-web/src/main/java/com/sap/espm/model/pdf/generator/InvoicePDFGenerator.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.sap.espm.model.pdf.generator; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import javax.naming.InitialContext; -import javax.naming.NamingException; - -import org.apache.chemistry.opencmis.client.api.Document; -import org.apache.chemistry.opencmis.client.api.Folder; -import org.apache.chemistry.opencmis.client.api.Session; -import org.apache.chemistry.opencmis.commons.PropertyIds; -import org.apache.chemistry.opencmis.commons.data.ContentStream; -import org.apache.chemistry.opencmis.commons.enums.VersioningState; -import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException; -import org.apache.pdfbox.exceptions.COSVisitorException; -import org.apache.pdfbox.pdmodel.PDDocument; -import org.apache.pdfbox.pdmodel.PDPage; -import org.apache.pdfbox.pdmodel.common.PDStream; -import org.apache.pdfbox.pdmodel.edit.PDPageContentStream; -import org.apache.pdfbox.pdmodel.font.PDFont; -import org.apache.pdfbox.pdmodel.font.PDType1Font; - -import com.sap.ecm.api.EcmService; -import com.sap.ecm.api.RepositoryOptions; -import com.sap.ecm.api.RepositoryOptions.Visibility; -import com.sap.espm.model.SalesOrderItem; -import com.sap.espm.model.builder.GenericInvoiceBuilder; -import com.sap.espm.model.builder.ReportBuilder; -import com.sap.espm.model.builder.pdf.CustomerSalesOrderBuilder; -import com.sap.espm.model.builder.pdf.ProductSalesOrderBuilder; -import com.sap.espm.model.builder.pdf.SalesOrderInvoiceBuilder; -import com.sap.espm.model.util.ReadProperties; - -/** - * Sales Order generator in PDF format - * - */ -public class InvoicePDFGenerator { - - GenericInvoiceBuilder invoiceBuilder; - - public InvoicePDFGenerator() { - List> builderList = new ArrayList<>( - 2); - builderList.add(new CustomerSalesOrderBuilder()); - builderList.add(new ProductSalesOrderBuilder()); - invoiceBuilder = new SalesOrderInvoiceBuilder(builderList); - - } - - public String generateInvoicePdf(List soiList) { - String reportPath = ""; - EcmService ecmSvc = null; - String repositoryUniqueName=""; - String repositorySecretKey=""; - Session openCmisSession = null; - InitialContext ctx; - try { - ctx = new InitialContext(); - String lookupName = "java:comp/env/" + "EcmService"; - ecmSvc = (EcmService) ctx.lookup(lookupName); - repositoryUniqueName = ReadProperties.getInstance().getValue("uniqueName"); - repositorySecretKey=ReadProperties.getInstance().getValue("secretKey"); - openCmisSession = ecmSvc.connect(repositoryUniqueName, repositorySecretKey); - } catch (NamingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (CmisObjectNotFoundException e) { - // repository does not exist, so try to create it - RepositoryOptions options = new RepositoryOptions(); - options.setUniqueName(repositoryUniqueName); - options.setRepositoryKey(repositorySecretKey); - options.setVisibility(Visibility.PROTECTED); - ecmSvc.createRepository(options); - // should be created now, so connect to it - openCmisSession = ecmSvc.connect(repositoryUniqueName, repositorySecretKey); - System.out.println("Connected in the catch block"); - } - - // access the root folder of the repository - Folder root = openCmisSession.getRootFolder(); - PDDocument invoiceDocument = new PDDocument(); - PDPage page = new PDPage(); - invoiceDocument.addPage(page); - PDPageContentStream contentStream = null; - - try { - contentStream = new PDPageContentStream(invoiceDocument, page); - contentStream.beginText(); - StringBuffer reportContent = invoiceBuilder - .generateInvoice(soiList); - - PDFont font = PDType1Font.TIMES_ROMAN; - contentStream.setFont(font, 10); - contentStream.moveTextPositionByAmount(100, 500); - String reportData = reportContent.toString(); - String[] reportArray = reportData.split("\\|"); - - for(int i=reportArray.length-1;i>=0;i--) - { - contentStream.drawString(reportArray[i]); - contentStream.moveTextPositionByAmount(0, 10); - - } - contentStream.endText(); - contentStream.close(); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - invoiceDocument.save(out); - invoiceDocument.close(); - Map properties = new HashMap(); - properties.put(PropertyIds.OBJECT_TYPE_ID, "cmis:document"); - SecureRandom random = new SecureRandom(); - long n = random.nextLong(); - String fileName = "Invoice" + n + ".pdf"; - properties.put(PropertyIds.NAME, fileName); - byte[] encoded = out.toByteArray(); - InputStream inputStream = new ByteArrayInputStream(encoded); - ContentStream contentStream1 = openCmisSession.getObjectFactory() - .createContentStream(fileName,-1 , - "application/pdf;charset=UTF-8", inputStream); - - Document cmisDocument=root.createDocument(properties, contentStream1, - VersioningState.NONE); - inputStream.close(); - out.close(); - reportPath=cmisDocument.getId(); - - }catch (IOException | COSVisitorException e) { - - System.out.println("Exception while writing the content to the pdf file."); - e.printStackTrace(); - } - - return reportPath; - } - -} diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/util/ReadProperties.java b/espm-cloud-web/src/main/java/com/sap/espm/model/util/ReadProperties.java index dba71f3..621da26 100644 --- a/espm-cloud-web/src/main/java/com/sap/espm/model/util/ReadProperties.java +++ b/espm-cloud-web/src/main/java/com/sap/espm/model/util/ReadProperties.java @@ -2,31 +2,69 @@ import java.io.IOException; import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** - * Reading property file - * + * This singleton class is used read the property file "config.properties" in + * the resources folder. + *

+ * As of now the property file holds the key and value used to connect to the + * Document Repository. This property file can be scaled up for further + * properties if need arises. */ public class ReadProperties{ + + /** + * Logger instance. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(ReadProperties.class); + /** + * The static instance of the class. + */ private static ReadProperties instance = null; + /** + * The {@link Properties} object that will hold the key and values. + */ private Properties props = null; + /** + * Private constructor used in the Singleton pattern. This will load the + * property file content and store the contents in the {@link Properties} + * object. + */ private ReadProperties(){ props = new Properties(); try { props.load(getClass().getResourceAsStream("/config.properties")); } catch (IOException e) { - e.printStackTrace(); + LOGGER.error(e.getMessage()); } } + /** + * Static getInstance method used to return the contents of the property + * file returned in a {@link Properties} object. + * + * @return - The Instance of this class. + */ public static synchronized ReadProperties getInstance(){ if (instance == null) instance = new ReadProperties(); return instance; } + /** + * This method will be used to fetch a particular value from the property + * file. + * + * @param propKey + * - The Key of the property. + * @return - The value of the property, null if does not exist. + */ public String getValue(String propKey){ return this.props.getProperty(propKey); } diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/util/ReflectionUtil.java b/espm-cloud-web/src/main/java/com/sap/espm/model/util/ReflectionUtil.java deleted file mode 100644 index 2e55d4f..0000000 --- a/espm-cloud-web/src/main/java/com/sap/espm/model/util/ReflectionUtil.java +++ /dev/null @@ -1,130 +0,0 @@ -/** - * - */ -package com.sap.espm.model.util; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.text.SimpleDateFormat; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -/** - * Utility class for Generating sales order headers and data - * - */ -public final class ReflectionUtil { - - private static final String DELIMITER = "|"; - - private static SimpleDateFormat formatter=new SimpleDateFormat("yyyy MM dd"); - - public static String generateEntityHeaders(Class clazz, Class annotationClass) { - String headers = "|"; - if (clazz != null) { - Field[] fields = clazz.getDeclaredFields(); - if (fields != null) { - for (Field field : fields) { - Annotation annotation = field.getAnnotation(annotationClass); - if (annotation != null) { - headers += field.getName() + DELIMITER; - } - } - } - } - return headers; - } - - public static String generateEntityData(Object object, Class annotationClass) - throws IllegalArgumentException, IllegalAccessException { - String data = "|"; - if (object != null) { - Field[] fields = object.getClass().getDeclaredFields(); - if (fields != null) { - for (Field field : fields) { - Annotation annotation = field.getAnnotation(annotationClass); - if (annotation != null) { - field.setAccessible(true); - - Object currentField = field.get(object); - if(currentField!=null && currentField instanceof GregorianCalendar){ - //convert to string date. - GregorianCalendar date = (GregorianCalendar) currentField; - - String dob = formatter.format(date.getTime()); - data += (dob != null) ? dob + DELIMITER - : fixedLengthString("", field.getName().length()) + DELIMITER; - } - else{ - data += (field.get(object) != null) ? field.get(object) + DELIMITER - : fixedLengthString("", field.getName().length()) + DELIMITER; - } - - - } - } - } - } - return data; - } - - public static Map generateReportData(Class clazz, - Class annotationClass, Object object) - throws IllegalArgumentException, IllegalAccessException { - Map reportData = new HashMap<>(); - if (clazz != null && object != null) { - Field[] fields = clazz.getDeclaredFields(); - if (fields != null) { - for (Field field : fields) { - Annotation annotation = field - .getAnnotation(annotationClass); - String name = field.getName(); - String data = ""; - if (annotation != null) { - field.setAccessible(true); - // headers += field.getName() + DELIMITER; - Object currentField = field.get(object); - if (currentField != null - && currentField instanceof GregorianCalendar) { - // convert to string date. - GregorianCalendar date = (GregorianCalendar) currentField; - - String dob = formatter.format(date.getTime()); - data += (dob != null) ? dob + "" : ""; - } else { - data += (field.get(object) != null) ? field - .get(object) + "" : ""; - } - reportData.put(name, data); - } - } - } - } - return reportData; - } - - public static void processReportMap(Map reportMap, StringBuffer reportBuffer){ - if(reportMap!=null && reportBuffer!=null){ - for(Entry entry : reportMap.entrySet()){ - String key = entry.getKey(); - String value = entry.getValue(); - reportBuffer.append(key + " : " + value); - reportBuffer.append("|"); - } - } - } - - - public static String fixedLengthString(String string, int length) { - return String.format("%1$" + length + "s", string); - } - - public static String padString(String str, int leng) { - for (int i = str.length(); i <= leng; i++) - str += " "; - return str; - } - -} diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/web/EspmProcessingExtension.java b/espm-cloud-web/src/main/java/com/sap/espm/model/web/EspmProcessingExtension.java index 76dd724..6551d84 100644 --- a/espm-cloud-web/src/main/java/com/sap/espm/model/web/EspmProcessingExtension.java +++ b/espm-cloud-web/src/main/java/com/sap/espm/model/web/EspmProcessingExtension.java @@ -28,13 +28,11 @@ public void extendWithOperation(JPAEdmSchemaView view) { @Override public void extendJPAEdmSchema(JPAEdmSchemaView arg0) { - // TODO Auto-generated method stub } @Override public InputStream getJPAEdmMappingModelStream(){ - // TODO Auto-generated method stub return null; } diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/web/EspmServiceFactory.java b/espm-cloud-web/src/main/java/com/sap/espm/model/web/EspmServiceFactory.java index eb92c9d..7ed8114 100644 --- a/espm-cloud-web/src/main/java/com/sap/espm/model/web/EspmServiceFactory.java +++ b/espm-cloud-web/src/main/java/com/sap/espm/model/web/EspmServiceFactory.java @@ -8,10 +8,17 @@ import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPARuntimeException; /** - * Odata JPA Processor implementation class + * Odata JPA Processor implementation class. This is required for the + * configuration of OData via the Olingo Framework. + *

+ * For more information regarding the Olingo framework configuration steps, + * refer to the documentation: https://olingo.apache.org/doc/odata4/index.html */ public class EspmServiceFactory extends ODataJPAServiceFactory { + /** + * The package that contains all the model classes. + */ private static final String PERSISTENCE_UNIT_NAME = "com.sap.espm.model"; @Override diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/web/EspmServiceFactoryFilter.java b/espm-cloud-web/src/main/java/com/sap/espm/model/web/EspmServiceFactoryFilter.java index 490e752..ea61bbe 100644 --- a/espm-cloud-web/src/main/java/com/sap/espm/model/web/EspmServiceFactoryFilter.java +++ b/espm-cloud-web/src/main/java/com/sap/espm/model/web/EspmServiceFactoryFilter.java @@ -12,14 +12,23 @@ import javax.servlet.http.HttpServletResponse; import org.apache.olingo.odata2.api.exception.ODataException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * - * Servlet Filter to block access to secure entities via non secure servlet + * Servlet {@link Filter} to block access to secure entities via non secure servlet * (/espm.svc/) + *

+ * Refer to the web.xml file on the declaration of the Filter. * */ public class EspmServiceFactoryFilter implements Filter { + + /** + * {@link Logger} implementation for logging. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(EspmServiceFactoryFilter.class); @Override public void init(FilterConfig filterConfig) throws ServletException { @@ -49,7 +58,7 @@ public void doFilter(ServletRequest request, ServletResponse response, } } catch (Exception e) { - throw new RuntimeException(e); + LOGGER.error(e.getMessage()); } } diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/web/JpaEntityManagerFactory.java b/espm-cloud-web/src/main/java/com/sap/espm/model/web/JpaEntityManagerFactory.java index 0380ae1..eeaa208 100644 --- a/espm-cloud-web/src/main/java/com/sap/espm/model/web/JpaEntityManagerFactory.java +++ b/espm-cloud-web/src/main/java/com/sap/espm/model/web/JpaEntityManagerFactory.java @@ -15,13 +15,31 @@ import com.sap.espm.model.util.Utility; /** - * Handles the singleton EntityManagerFactory instance. + * Handles the singleton {@link EntityManagerFactory} instance. + *

+ * This class is responsible for fetching the details of the {@link DataSource} + * that has the connection related details (Host, username, password) on how to + * connect to the data source. + *

+ * Note - This class fetches the {@link DataSource} details via JNDI, so + * ensure that you have the DataSource configured as a JNDI lookup variable in + * the respective ServletContainer where the application is deployed. */ public class JpaEntityManagerFactory { + /** + * The JNDI name of the DataSource. + */ public static final String DATA_SOURCE_NAME = "java:comp/env/jdbc/DefaultDB"; + + /** + * The package name which contains all the model classes. + */ public static final String PERSISTENCE_UNIT_NAME = "com.sap.espm.model"; + /** + * The static {@link EntityManagerFactory} + */ private static EntityManagerFactory entityManagerFactory = null; /** diff --git a/espm-cloud-web/src/main/java/com/sap/espm/model/web/StartupServlet.java b/espm-cloud-web/src/main/java/com/sap/espm/model/web/StartupServlet.java index 7bb24f6..99f7baa 100644 --- a/espm-cloud-web/src/main/java/com/sap/espm/model/web/StartupServlet.java +++ b/espm-cloud-web/src/main/java/com/sap/espm/model/web/StartupServlet.java @@ -1,23 +1,41 @@ package com.sap.espm.model.web; import javax.persistence.EntityManagerFactory; +import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.sap.espm.model.data.DataLoader; /** - * The Startup Servlet loads intitial data and provides some additional basic + * The Startup {@link Servlet} loads intitial data and provides some additional basic * services. + * */ public class StartupServlet extends HttpServlet { + /** + * Serial Id. + */ private static final long serialVersionUID = 1L; + + /** + * Static {@link EntityManagerFactory} used to connect to the DataSource. + */ private static EntityManagerFactory emf; - /* + /** + * {@link Logger} implementation. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(StartupServlet.class); + + /** * Retrieves the JPA entity manager factory and loads initial data into the * ESPM model tables. + * */ @Override public void init() throws ServletException { @@ -25,12 +43,14 @@ public void init() throws ServletException { emf = JpaEntityManagerFactory.getEntityManagerFactory(); DataLoader loader = new DataLoader(emf); loader.loadData(); + } catch (Exception e) { + LOGGER.error(e.getMessage()); throw new ServletException(e); } } - /* + /** * Closes the JPA entity manager factory. */ @Override diff --git a/espm-cloud-web/src/main/webapp/WEB-INF/web.xml b/espm-cloud-web/src/main/webapp/WEB-INF/web.xml index d8001e1..63bf267 100644 --- a/espm-cloud-web/src/main/webapp/WEB-INF/web.xml +++ b/espm-cloud-web/src/main/webapp/WEB-INF/web.xml @@ -107,6 +107,6 @@ CmisRead - /CmisRead + /espm.svc/CmisRead \ No newline at end of file diff --git a/espm-cloud-web/src/main/webapp/retailer/controller/SalesOrder.controller.js b/espm-cloud-web/src/main/webapp/retailer/controller/SalesOrder.controller.js index 3316c58..b08c73e 100644 --- a/espm-cloud-web/src/main/webapp/retailer/controller/SalesOrder.controller.js +++ b/espm-cloud-web/src/main/webapp/retailer/controller/SalesOrder.controller.js @@ -21,6 +21,11 @@ sap.ui.define([ * @memberOf com.sap.espm.retailer.view.SalesOrder */ onInit: function() { + + var deviceModel = new sap.ui.model.json.JSONModel({ + isPhone: sap.ui.Device.system.phone + }); + this.getView().setModel(deviceModel, "device"); }, @@ -95,6 +100,10 @@ sap.ui.define([ var bindString = context + "/SalesOrderItems"; oTable.bindItems(bindString, oTemplate); + if(this.getView().getModel("device").oData.isPhone){ + this.byId("splitContId").to(this.byId("detailPageId")); + } + }, handleSearch : function (evt) @@ -192,7 +201,13 @@ sap.ui.define([ }, onNavBack: function(){ window.history.go(-1); - } + }, + + handleNavButtonPress: function(){ + var oSplitCont = this.byId("splitContId"); + var oMaster = oSplitCont.getMasterPages()[0]; + oSplitCont.toMaster(oMaster); + } }); diff --git a/espm-cloud-web/src/main/webapp/retailer/fragment/SupplierCard.fragment.xml b/espm-cloud-web/src/main/webapp/retailer/fragment/SupplierCard.fragment.xml index f7d7a5e..41799a9 100644 --- a/espm-cloud-web/src/main/webapp/retailer/fragment/SupplierCard.fragment.xml +++ b/espm-cloud-web/src/main/webapp/retailer/fragment/SupplierCard.fragment.xml @@ -7,7 +7,7 @@ - + diff --git a/espm-cloud-web/src/main/webapp/retailer/i18n/i18n.properties b/espm-cloud-web/src/main/webapp/retailer/i18n/i18n.properties index 692f602..87010c1 100644 --- a/espm-cloud-web/src/main/webapp/retailer/i18n/i18n.properties +++ b/espm-cloud-web/src/main/webapp/retailer/i18n/i18n.properties @@ -31,7 +31,7 @@ sales.masterPageTitle=Sales order list sales.masterSearchPlaceholder=Search sales.masterSearchTooltip=Search sales.masterListNoDataText=Sales order List is empty -sales.detailPageTitle=Sales order +sales.detailPageTitle=Sales order Details sales.address=Address sales.customerName=Customer name sales.email=Email diff --git a/espm-cloud-web/src/main/webapp/retailer/test/integration/AllJourneys.js b/espm-cloud-web/src/main/webapp/retailer/test/integration/AllJourneys.js new file mode 100644 index 0000000..808f774 --- /dev/null +++ b/espm-cloud-web/src/main/webapp/retailer/test/integration/AllJourneys.js @@ -0,0 +1,12 @@ +jQuery.sap.require("sap.ui.qunit.qunit-css"); +jQuery.sap.require("sap.ui.thirdparty.qunit"); +jQuery.sap.require("sap.ui.qunit.qunit-junit"); +jQuery.sap.require("sap.ui.test.opaQunit"); +jQuery.sap.require("sap.ui.test.Opa5"); +//Load the Page Objects +jQuery.sap.require("com.sap.espm.retailer.test.integration.pages.HomePage"); +jQuery.sap.require("com.sap.espm.retailer.test.integration.pages.StockPage"); +jQuery.sap.require("com.sap.espm.retailer.test.integration.pages.SalesOrderPage"); + +//Load the journeys +jQuery.sap.require("com.sap.espm.retailer.test.integration.HomeJourney"); \ No newline at end of file diff --git a/espm-cloud-web/src/main/webapp/retailer/test/integration/HomeJourney.js b/espm-cloud-web/src/main/webapp/retailer/test/integration/HomeJourney.js new file mode 100644 index 0000000..4f72c93 --- /dev/null +++ b/espm-cloud-web/src/main/webapp/retailer/test/integration/HomeJourney.js @@ -0,0 +1,60 @@ +sap.ui.define( + [], + function() { + "use strict"; + + QUnit.module(""); + + + opaTest("Home page with Tile container", function(Given, When, Then) { + + Given.iStartMyAppInAFrame("../../index.html"); + //When.onHome.iWaitUntilTheBusyIndicatorIsGone(); + Then.onHome.iSeeTileContainer(); + + }); + + opaTest("Choose stock information tile container", function(Given, When, Then) { + + //Actions + When.onHome.iClickStockInformationTile(); + //Assertions + Then.onStock.iSeeStockProductListView(); + + }); + + opaTest("Update stock information for a single product", function(Given, When, Then) { + + //Actions + When.onStock.iClickonStockUpdateButton(); + When.onStock.iEnterStockValue(); + When.onStock.iClickonSubmitButton(); + //Assertions + Then.onStock.iSeeStockProductListView(); + Then.onStock.iGoBack(); + + }); + + opaTest("Choose sales order tile container", function(Given, When, Then) { + + //Actions + When.onHome.iClickSalesOrderTile(); + //Assertions + Then.onSales.iSeeSalesOrderListView(); + + }); + + opaTest("Approve sales order", function(Given, When, Then) { + + //Actions + When.onSales.iClickSalesOrderListItem(); + When.onSales.iPressApproveButton(); + When.onSales.iPressApproveDialogOkButton(); + When.onSales.iClickSalesOrderListItem(); + //Assertions + Then.onSales.iSeeSalesOrderListView(); + + }); + + } +); \ No newline at end of file diff --git a/espm-cloud-web/src/main/webapp/retailer/test/integration/opaTests.qunit.html b/espm-cloud-web/src/main/webapp/retailer/test/integration/opaTests.qunit.html new file mode 100644 index 0000000..496eb63 --- /dev/null +++ b/espm-cloud-web/src/main/webapp/retailer/test/integration/opaTests.qunit.html @@ -0,0 +1,24 @@ + + + + Opa tests for ESPM + + + + + + + + + +

+
+ + \ No newline at end of file diff --git a/espm-cloud-web/src/main/webapp/retailer/test/integration/pages/HomePage.js b/espm-cloud-web/src/main/webapp/retailer/test/integration/pages/HomePage.js new file mode 100644 index 0000000..04c1162 --- /dev/null +++ b/espm-cloud-web/src/main/webapp/retailer/test/integration/pages/HomePage.js @@ -0,0 +1,55 @@ +sap.ui.define([ + "sap/ui/test/Opa5", + "sap/ui/test/matchers/AggregationLengthEquals", + "sap/ui/test/matchers/AggregationFilled", + "sap/ui/test/matchers/PropertyStrictEquals" + ], + function(Opa5) { + "use strict"; + + var sViewName = "com.sap.espm.retailer.view.Home"; + Opa5.createPageObjects({ + onHome: { + actions: { + + iClickStockInformationTile: function() { + return this.waitFor({ + id: "container", + viewName: sViewName, + success: function(tile) { + tile.getTiles()[1].$().trigger("tap"); + }, + errorMessage: "Not able to click on Tile button." + }); + }, + iClickSalesOrderTile: function() { + return this.waitFor({ + id: "container", + viewName: sViewName, + success: function(tile) { + tile.getTiles()[0].$().trigger("tap"); + }, + errorMessage: "Not able to click on Tile button." + }); + } + }, + + assertions: { + + iSeeTileContainer: function() { + return this.waitFor({ + id: "container", + viewName: sViewName, + success: function(oPL) { + Opa5.assert.ok(oPL, "Tile container successfully loaded"); + }, + errorMessage: "Did not find the Home page" + }); + } + + } + + } + }); + } +); \ No newline at end of file diff --git a/espm-cloud-web/src/main/webapp/retailer/test/integration/pages/SalesOrderPage.js b/espm-cloud-web/src/main/webapp/retailer/test/integration/pages/SalesOrderPage.js new file mode 100644 index 0000000..c6d7ce2 --- /dev/null +++ b/espm-cloud-web/src/main/webapp/retailer/test/integration/pages/SalesOrderPage.js @@ -0,0 +1,92 @@ +sap.ui.define([ + "sap/ui/test/Opa5", + "sap/ui/test/matchers/AggregationLengthEquals", + "sap/ui/test/matchers/AggregationFilled", + "sap/ui/test/matchers/PropertyStrictEquals" + ], + function(Opa5) { + "use strict"; + + var sViewName = "com.sap.espm.retailer.view.SalesOrder"; + Opa5.createPageObjects({ + onSales: { + actions: { + + iClickSalesOrderListItem: function() { + return this.waitFor({ + id: "list", + //controlType: "sap.m.List", + viewName: sViewName, + matchers: new sap.ui.test.matchers.AggregationFilled({ + name: "items" + + }), + + success: function(oPL) { + oPL.getItems()[0].fireEvent("press"); + Opa5.assert.ok(oPL, "Found the sales order list"); + }, + errorMessage: "Did not find the sales products list" + }); + }, + + iPressApproveButton: function() { + return this.waitFor({ + id: "approveButtonId", + viewName: sViewName, + success: function(aButtons) { + aButtons.$().trigger("tap"); + }, + errorMessage: "Did not find the approve button." + }); + }, + iPressApproveDialogOkButton: function(){ + var oOrderNowButton = null; + this.waitFor({ + searchOpenDialogs : true, + controlType : "sap.m.Button", + check : function (aButtons) { + return aButtons.filter(function (oButton) { + if(oButton.getText() !== "OK") { + return false; + } + + oOrderNowButton = oButton; + return true; + }); + }, + success : function (button) { + oOrderNowButton.$().trigger("tap"); + Opa5.assert.ok(button,"Sales order has been approved"); + }, + errorMessage : "Did not find the OK button" + }); + return this; + } + }, + + assertions: { + + iSeeSalesOrderListView: function() { + return this.waitFor({ + id: "list", + //controlType: "sap.m.List", + viewName: sViewName, + matchers: new sap.ui.test.matchers.AggregationFilled({ + name: "items" + + }), + + success: function(oPL) { + Opa5.assert.ok(oPL, "Found the sales order list"); + }, + errorMessage: "Did not find the sales products list" + }); + } + + } + + } + }); + } +); \ No newline at end of file diff --git a/espm-cloud-web/src/main/webapp/retailer/test/integration/pages/StockPage.js b/espm-cloud-web/src/main/webapp/retailer/test/integration/pages/StockPage.js new file mode 100644 index 0000000..648b80a --- /dev/null +++ b/espm-cloud-web/src/main/webapp/retailer/test/integration/pages/StockPage.js @@ -0,0 +1,111 @@ +sap.ui.define([ + "sap/ui/test/Opa5", + "sap/ui/test/matchers/AggregationLengthEquals", + "sap/ui/test/matchers/AggregationFilled", + "sap/ui/test/matchers/PropertyStrictEquals" + ], + function(Opa5) { + "use strict"; + + var sViewName = "com.sap.espm.retailer.view.StockInformation"; + Opa5.createPageObjects({ + onStock: { + actions: { + + iClickonStockUpdateButton: function() { + return this.waitFor({ + id: "catalogTable", + //controlType: "sap.m.Table", + viewName: sViewName, + matchers: new sap.ui.test.matchers.AggregationFilled({ + name: "items" + }), + success: function(oSCTab) { + oSCTab.getItems()[0].getCells()[4].fireEvent("press"); + Opa5.assert.ok(oSCTab, "Fired an event for stock update button"); + }, + errorMessage: "Failed to find the table" + }); + }, + iEnterStockValue: function(){ + var oOrderNowButton = null; + this.waitFor({ + searchOpenDialogs : true, + controlType : "sap.m.Input", + check : function (aInputs) { + aInputs[0].setValue("19"); + aInputs[0].fireEvent("liveChange"); + return true; + }, + success : function (field) { + Opa5.assert.ok(field, "Updated the stock input field"); + }, + errorMessage : "Did not find the stock input field" + }); + return this; + }, + + iClickonSubmitButton: function(){ + var oOrderNowButton = null; + this.waitFor({ + searchOpenDialogs : true, + controlType : "sap.m.Button", + check : function (aButtons) { + return aButtons.filter(function (oButton) { + if(oButton.getText() !== "Submit") { + return false; + } + + oOrderNowButton = oButton; + return true; + }); + }, + success : function (button) { + oOrderNowButton.$().trigger("tap"); + Opa5.assert.ok(button,"Clicked on submit button"); + }, + errorMessage : "Did not find the submit button" + }); + return this; + } + + }, + + assertions: { + + iGoBack: function() { + return this.waitFor({ + //id: "catalogTable", + controlType: "sap.m.Page", + viewName: sViewName, + success: function(oPL) { + oPL[0]._navBtn.firePress(); + Opa5.assert.ok(oPL, "Go back to home page"); + }, + errorMessage: "Did not find the back button" + }); + }, + + iSeeStockProductListView: function() { + return this.waitFor({ + //id: "catalogTable", + controlType: "sap.m.Table", + viewName: sViewName, + matchers: new sap.ui.test.matchers.AggregationFilled({ + name: "items" + + }), + + success: function(oPL) { + Opa5.assert.ok(oPL, "Found the stock products list"); + }, + errorMessage: "Did not find the stock products list" + }); + } + + } + + } + }); + } +); \ No newline at end of file diff --git a/espm-cloud-web/src/main/webapp/retailer/test/integration/test.html b/espm-cloud-web/src/main/webapp/retailer/test/integration/test.html new file mode 100644 index 0000000..962624c --- /dev/null +++ b/espm-cloud-web/src/main/webapp/retailer/test/integration/test.html @@ -0,0 +1,25 @@ + + + ESPM RETAILER OPA5 TEST + + + + + + +

ESPM RETAILER OPA5 TEST

+ +

In this sample app for the testing tutorial we will test application functionality with OPA5

+ +

+These files can be used to run the application as a standalone application in the SAP Web IDE or after building and +serving with bower/grunt (expects a UI5 installation available at the server root, so this will not work without this +build and the grunt-based server). + +

For more documentation please read the UI5 Developer Guide.

+ + \ No newline at end of file diff --git a/espm-cloud-web/src/main/webapp/retailer/view/SalesOrder.view.xml b/espm-cloud-web/src/main/webapp/retailer/view/SalesOrder.view.xml index 8bb2b4d..5790607 100644 --- a/espm-cloud-web/src/main/webapp/retailer/view/SalesOrder.view.xml +++ b/espm-cloud-web/src/main/webapp/retailer/view/SalesOrder.view.xml @@ -2,7 +2,7 @@ xmlns:html="http://www.w3.org/1999/xhtml"> - + @@ -37,7 +37,7 @@ - + diff --git a/espm-cloud-web/src/main/webapp/webshop/controller/Checkout.controller.js b/espm-cloud-web/src/main/webapp/webshop/controller/Checkout.controller.js index 8d2a8cd..2576e30 100644 --- a/espm-cloud-web/src/main/webapp/webshop/controller/Checkout.controller.js +++ b/espm-cloud-web/src/main/webapp/webshop/controller/Checkout.controller.js @@ -177,7 +177,7 @@ sap.ui.define([ var firstName = this.byId("firstNameId").getValue(); var lastName = this.byId("lastnameId").getValue(); var birthDate = this.byId("birthId").getValue(); - var eMail = this.byId("newEmailId").getValue(); + var eMail = this.byId("newEmailId").getValue().toLowerCase(); var street = this.byId("streetId").getValue(); var city = this.byId("cityId").getValue(); var postalCode = this.byId("postalId").getValue(); @@ -250,7 +250,7 @@ sap.ui.define([ var utctime = Date.parse(date); date = "/Date("+utctime+")/"; var customer = { - "EmailAddress":this.byId("newEmailId").getValue(), + "EmailAddress":this.byId("newEmailId").getValue().toLowerCase(), "LastName":this.byId("lastnameId").getValue(), "FirstName":this.byId("firstNameId").getValue(), "DateOfBirth":date, @@ -322,7 +322,7 @@ sap.ui.define([ type: "PUT", async: true, contentType:"application/json; charset=utf-8", - url: oData.d.__metadata.id + "/$links/Customer", + url: "/espm-cloud-web/espm.svc/SalesOrderHeaders('" + oData.d.SalesOrderId + "')/$links/Customer", data :JSON.stringify(dataJson), success: function() { @@ -343,7 +343,7 @@ sap.ui.define([ async: true, dataType: "json", contentType:"application/json; charset=utf-8", - url: data.d.results[j].__metadata.id + "/$links/Product", + url: "/espm-cloud-web/espm.svc/SalesOrderItems(ItemNumber=" + data.d.results[j].ItemNumber + ",SalesOrderId='"+ data.d.results[j].SalesOrderId + "')/$links/Product", data :JSON.stringify(productDataJson), success: function() { @@ -423,12 +423,12 @@ sap.ui.define([ var sFunctionImportEmailParam; if(buttonIndex === 0){ if(that.byId("newEmailId").getValue().length !== 0){ - sFunctionImportEmailParam = "EmailAddress='" + that.byId("newEmailId").getValue() + "'"; + sFunctionImportEmailParam = "EmailAddress='" + that.byId("newEmailId").getValue().toLowerCase() + "'"; } } else{ if(that.byId("existingEmailId").getValue().length !== 0){ - sFunctionImportEmailParam = "EmailAddress='" + this.byId("existingEmailId").getValue() + "'"; + sFunctionImportEmailParam = "EmailAddress='" + this.byId("existingEmailId").getValue().toLowerCase() + "'"; } } @@ -463,7 +463,7 @@ sap.ui.define([ var oBundle = this.getView().getModel('i18n').getResourceBundle(); if(this.validateEmail(this.byId("existingEmailId").getValue()) === true){ - var sFunctionImportEmailParam = "EmailAddress='" + this.byId("existingEmailId").getValue() + "'"; + var sFunctionImportEmailParam = "EmailAddress='" + this.byId("existingEmailId").getValue().toLowerCase() + "'"; var aParams = []; aParams.push(sFunctionImportEmailParam); diff --git a/espm-cloud-web/src/main/webapp/webshop/controller/SalesOrder.controller.js b/espm-cloud-web/src/main/webapp/webshop/controller/SalesOrder.controller.js index 634fad6..a0bba3a 100644 --- a/espm-cloud-web/src/main/webapp/webshop/controller/SalesOrder.controller.js +++ b/espm-cloud-web/src/main/webapp/webshop/controller/SalesOrder.controller.js @@ -77,7 +77,7 @@ sap.ui.define([ new sap.m.Label({text:oBundle.getText("soPopup.emailAddress")}), new sap.m.Input({ liveChange:function(oEvent){ - emailId = oEvent.getSource().getValue(); + emailId = oEvent.getSource().getValue().toLowerCase(); } }) @@ -163,7 +163,7 @@ sap.ui.define([ handleListItemPress: function(event){ - pdfURL = "/espm-cloud-web/CmisRead?objectId="+event.getSource().getBindingContext().getObject("InvoiceLink"); + pdfURL = "/espm-cloud-web/espm.svc/CmisRead?objectId="+event.getSource().getBindingContext().getObject("InvoiceLink"); this.getView().byId("detailPageId").setVisible(true); diff --git a/espm-cloud-web/src/main/webapp/webshop/i18n/i18n.properties b/espm-cloud-web/src/main/webapp/webshop/i18n/i18n.properties index b78572f..5be5e1c 100644 --- a/espm-cloud-web/src/main/webapp/webshop/i18n/i18n.properties +++ b/espm-cloud-web/src/main/webapp/webshop/i18n/i18n.properties @@ -150,3 +150,4 @@ soPopup.cancel=Cancel soPopup.errorMessage=Check your input and try again soPopup.fieldEmpty=Field is empty soPopup.invalidEmailAddress=You have entered an invalid E-mail address! +soPopup.notImplemented=viewing your orders is not yet implemented diff --git a/espm-cloud-web/src/main/webapp/webshop/test/integration/AllJourneys.js b/espm-cloud-web/src/main/webapp/webshop/test/integration/AllJourneys.js new file mode 100644 index 0000000..470bf9e --- /dev/null +++ b/espm-cloud-web/src/main/webapp/webshop/test/integration/AllJourneys.js @@ -0,0 +1,13 @@ +jQuery.sap.require("sap.ui.qunit.qunit-css"); +jQuery.sap.require("sap.ui.thirdparty.qunit"); +jQuery.sap.require("sap.ui.qunit.qunit-junit"); +jQuery.sap.require("sap.ui.test.opaQunit"); +jQuery.sap.require("sap.ui.test.Opa5"); +//Load the Page Objects +jQuery.sap.require("com.sap.espm.shop.test.integration.pages.HomePage"); +jQuery.sap.require("com.sap.espm.shop.test.integration.pages.DetailPage"); +jQuery.sap.require("com.sap.espm.shop.test.integration.pages.CartPage"); +jQuery.sap.require("com.sap.espm.shop.test.integration.pages.CheckoutPage"); + +//Load the journeys +jQuery.sap.require("com.sap.espm.shop.test.integration.HomeJourney"); \ No newline at end of file diff --git a/espm-cloud-web/src/main/webapp/webshop/test/integration/HomeJourney.js b/espm-cloud-web/src/main/webapp/webshop/test/integration/HomeJourney.js new file mode 100644 index 0000000..bfc3409 --- /dev/null +++ b/espm-cloud-web/src/main/webapp/webshop/test/integration/HomeJourney.js @@ -0,0 +1,102 @@ +sap.ui.define( + [], + function() { + "use strict"; + + QUnit.module(""); + + + opaTest("Home page with products List", function(Given, When, Then) { + + Given.iStartMyAppInAFrame("../../index.html"); + //When.onHome.iWaitUntilTheBusyIndicatorIsGone(); + Then.onHome.iSeeProductListView(); + + }); + + opaTest("Search for the product in the list items", function(Given, When, Then) { + + //Actions + When.onHome.iGetTitleOfFirstItem(); + When.onHome.iSearchForTheFirstObject(); + //Assertions + Then.onHome.iCheckIfItemSearchedIsMatchingOnMasterList(); + + }); + + opaTest("Select the first item in the list", function(Given, When, Then) { + + //Actions + When.onHome.iSelectItemFromTheProductList(); + //Assertions + Then.onDetail.iCheckIfItemGotSelected(); + + }); + + opaTest("Add product to the cart and navigate to cart", function(Given, When, Then) { + + //Actions + When.onDetail.iPressAddToCartButton(); + //Assertions + Then.onDetail.iCheckIfItemGotAddedToCart(); + + }); + + opaTest("update quantity in the cart page", function(Given, When, Then) { + + //Actions + When.onCart.iChangeQuantityinCart(); + //Assertions + Then.onCart.iCheckIfQunatityUpdated(); + + + }); + + opaTest("Navigate to checkout page", function(Given, When, Then) { + + //Actions + When.onCart.iPressOnCheckoutButton(); + //Assertions + Then.onCheckout.iSeeCheckoutView(); + + + }); + + opaTest("Fill new customer personal details", function(Given, When, Then) { + + //Actions + When.onCheckout.iClickOnWizardStep2(); + When.onCheckout.iChooseNewCustomerRadiotButton(); + When.onCheckout.iFillNewCustomerDetails(); + //Assertions + Then.onCheckout.iSeeCheckoutView(); + + + }); + + opaTest("Fill new customer card details", function(Given, When, Then) { + + //Actions + When.onCheckout.iClickOnWizardStep3(); + When.onCheckout.iFillNewCustomerCardDetails(); + When.onCheckout.iClickOnWizardReview(); + //Assertions + Then.onCheckout.iSeeCheckoutView(); + + + }); + + opaTest("Place an order", function(Given, When, Then) { + + //Actions + When.onCheckout.iPressOnOrderButton(); + //Assertions + Then.onCheckout.iSeeCheckoutView(); + + + }); + + + + } +); \ No newline at end of file diff --git a/espm-cloud-web/src/main/webapp/webshop/test/integration/opaTests.qunit.html b/espm-cloud-web/src/main/webapp/webshop/test/integration/opaTests.qunit.html new file mode 100644 index 0000000..3b5d458 --- /dev/null +++ b/espm-cloud-web/src/main/webapp/webshop/test/integration/opaTests.qunit.html @@ -0,0 +1,24 @@ + + + + Opa tests for ESPM + + + + + + + + + +
+
+ + \ No newline at end of file diff --git a/espm-cloud-web/src/main/webapp/webshop/test/integration/pages/CartPage.js b/espm-cloud-web/src/main/webapp/webshop/test/integration/pages/CartPage.js new file mode 100644 index 0000000..9fd7637 --- /dev/null +++ b/espm-cloud-web/src/main/webapp/webshop/test/integration/pages/CartPage.js @@ -0,0 +1,67 @@ +sap.ui.define([ + "sap/ui/test/Opa5", + "sap/ui/test/matchers/AggregationLengthEquals", + "sap/ui/test/matchers/AggregationFilled", + "sap/ui/test/matchers/PropertyStrictEquals" + ], + function(Opa5) { + "use strict"; + var sViewName = "com.sap.espm.shop.view.Shoppingcart"; + + Opa5.createPageObjects({ + onCart: { + actions: { + + iChangeQuantityinCart: function() { + // Change the quantity of the shopping item + return this.waitFor({ + id: "shoppingCartTable", + //controlType: "sap.m.Table", + viewName: sViewName, + matchers: new sap.ui.test.matchers.AggregationFilled({ + name: "items" + }), + success: function(oSCTab) { + oSCTab.getItems()[0].getCells()[2].setValue("2"); + oSCTab.getItems()[0].getCells()[2].fireEvent("change"); + Opa5.assert.ok(oSCTab, "Quantitiy of products changed"); + }, + errorMessage: "Failed to find the field" + }); + }, + iPressOnCheckoutButton: function() { + return this.waitFor({ + id: "btnCheckOut", + viewName: sViewName, + success: function(aButtons) { + aButtons.$().trigger("tap"); + }, + errorMessage: "Did not find the checkout button." + }); + } + }, + + assertions: { + + iCheckIfQunatityUpdated: function() { + return this.waitFor({ + id: "btnShoppingCartHeader", + viewName: sViewName, + matchers: new sap.ui.test.matchers.PropertyStrictEquals({ + name: "text", + value: "2" + }), + success: function(cartButton) { + + Opa5.assert.ok(cartButton, "Qunatity has been updated"); + }, + errorMessage: "Failed to update quantity" + }); + } + + } + + } + }); + } +); \ No newline at end of file diff --git a/espm-cloud-web/src/main/webapp/webshop/test/integration/pages/CheckoutPage.js b/espm-cloud-web/src/main/webapp/webshop/test/integration/pages/CheckoutPage.js new file mode 100644 index 0000000..1cbe9ba --- /dev/null +++ b/espm-cloud-web/src/main/webapp/webshop/test/integration/pages/CheckoutPage.js @@ -0,0 +1,140 @@ +sap.ui.define([ + "sap/ui/test/Opa5", + "sap/ui/test/matchers/AggregationLengthEquals", + "sap/ui/test/matchers/AggregationFilled", + "sap/ui/test/matchers/PropertyStrictEquals" + ], + function(Opa5) { + "use strict"; + + var sViewName = "com.sap.espm.shop.view.Checkout"; + var sFragmentReviewName = "com.sap.espm.shop.view.fragment.ReviewPage"; + + Opa5.createPageObjects({ + onCheckout: { + actions: { + + iClickOnWizardStep2: function() { + return this.waitFor({ + id:"checkoutWizard", + viewName: sViewName, + success: function(wizard) { + wizard._handleNextButtonPress(); + }, + errorMessage: "Did not find the wizard" + }); + }, + + iChooseNewCustomerRadiotButton: function() { + return this.waitFor({ + id: "newCustomerId", + viewName: sViewName, + success: function(radioButton) { + radioButton.$().trigger("tap"); + }, + errorMessage: "Did not find the add to cart button." + }); + }, + + iFillNewCustomerDetails: function() { + return this.waitFor({ + id: "newFormId", + viewName: sViewName, + success: function(newForm) { + newForm.getContent()[1].setValue("Karthik"); + newForm.getContent()[2].setValue("Ram"); + newForm.getContent()[4].setValue("ka142345@gmail.com"); + newForm.getContent()[6].setValue("Feb 1, 2000"); + newForm.getContent()[8].setValue("345"); + newForm.getContent()[9].setValue("Gotham"); + newForm.getContent()[10].setValue("7864"); + newForm.getContent()[11].setValue("IN"); + Opa5.assert.ok(newForm, "New customer details got filled"); + + }, + errorMessage: "Did not find the Form." + }); + }, + + iClickOnWizardStep3: function() { + return this.waitFor({ + id:"checkoutWizard", + viewName: sViewName, + success: function(wizard) { + wizard._handleNextButtonPress(); + }, + errorMessage: "Did not find the wizard" + }); + }, + + iFillNewCustomerCardDetails: function() { + return this.waitFor({ + id: "cardFormId", + viewName: sViewName, + success: function(newForm) { + newForm.getContent()[2].setValue("Karthik Ram"); + newForm.getContent()[4].setValue("3452 2345 3212 1235"); + newForm.getContent()[6].setValue("4312"); + Opa5.assert.ok(newForm, "New customer card details got filled"); + + }, + errorMessage: "Did not find the Form." + }); + }, + iClickOnWizardReview: function() { + return this.waitFor({ + id:"checkoutWizard", + viewName: sViewName, + success: function(wizard) { + wizard._handleNextButtonPress(); + }, + errorMessage: "Did not find the wizard" + }); + }, + iPressOnOrderButton: function() { + return this.waitFor({ + id: "wizardNavContainer", + viewName: sViewName, + success: function(navContainer) { + navContainer.getCurrentPage().getFooter().getContentRight()[0].$().trigger("tap"); + }, + errorMessage: "Did not find the checkout button." + }); + } + + }, + + assertions: { + + iSeeCheckoutView: function() { + return this.waitFor({ + controlType: "sap.m.Table", + viewName: sViewName, + matchers: new sap.ui.test.matchers.AggregationFilled({ + name: "items" + + }), + + success: function(oPL) { + Opa5.assert.ok(oPL, "Checkout page loaded"); + }, + errorMessage: "Failed to load the checkout page" + }); + }, + iSeeSalesOrderMessageBox: function(){ + return this.waitFor({ + controlType: "sap.m.MessageBox", + viewName: sViewName, + success: function(messageBox) { + Opa5.assert.ok(messageBox, "Sales order has been created"); + }, + errorMessage: "Sales order creation has been failed" + }); + } + + } + + } + }); + } +); \ No newline at end of file diff --git a/espm-cloud-web/src/main/webapp/webshop/test/integration/pages/DetailPage.js b/espm-cloud-web/src/main/webapp/webshop/test/integration/pages/DetailPage.js new file mode 100644 index 0000000..c5fa20a --- /dev/null +++ b/espm-cloud-web/src/main/webapp/webshop/test/integration/pages/DetailPage.js @@ -0,0 +1,61 @@ +sap.ui.define([ + "sap/ui/test/Opa5", + "sap/ui/test/matchers/AggregationLengthEquals", + "sap/ui/test/matchers/AggregationFilled", + "sap/ui/test/matchers/PropertyStrictEquals" + ], + function(Opa5) { + "use strict"; + + var sViewName = "com.sap.espm.shop.view.ProductDetail"; + Opa5.createPageObjects({ + onDetail: { + actions: { + + iPressAddToCartButton: function() { + return this.waitFor({ + id: "btnAddToCart", + viewName: sViewName, + success: function(aButtons) { + aButtons.$().trigger("tap"); + }, + errorMessage: "Did not find the add to cart button." + }); + } + }, + + assertions: { + + iCheckIfItemGotSelected: function() { + return this.waitFor({ + id: "productId", + viewName: sViewName, + success: function(oPL) { + Opa5.assert.ok(oPL, "Detail page successfully loaded"); + }, + errorMessage: "Did not find the detail page" + }); + }, + iCheckIfItemGotAddedToCart: function() { + return this.waitFor({ + id: "btnProductHeader", + viewName: sViewName, + matchers: new sap.ui.test.matchers.PropertyStrictEquals({ + name: "text", + value: "1" + }), + success: function(cartButton) { + + cartButton.$().trigger("tap"); + Opa5.assert.ok(cartButton, "product added to cart and navigate to cart page"); + }, + errorMessage: "product added to cart failed" + }); + } + + } + + } + }); + } +); \ No newline at end of file diff --git a/espm-cloud-web/src/main/webapp/webshop/test/integration/pages/HomePage.js b/espm-cloud-web/src/main/webapp/webshop/test/integration/pages/HomePage.js new file mode 100644 index 0000000..db45da1 --- /dev/null +++ b/espm-cloud-web/src/main/webapp/webshop/test/integration/pages/HomePage.js @@ -0,0 +1,137 @@ +sap.ui.define([ + "sap/ui/test/Opa5", + "sap/ui/test/matchers/AggregationLengthEquals", + "sap/ui/test/matchers/AggregationFilled", + "sap/ui/test/matchers/PropertyStrictEquals", + "sap/ui/test/actions/Press" + ], + function(Opa5, AggregationLengthEquals, AggregationFilled, PropertyStrictEquals, Press) { + "use strict"; + + var sViewName = "com.sap.espm.shop.view.Home"; + var sFirstObjectTitle; + + function enterSomethingInASearchField(oSearchField, oSearchParams) { + oSearchParams = oSearchParams || {}; + + if (oSearchParams.searchValue) { + oSearchField.setValue(oSearchParams.searchValue); + } + + if (oSearchParams.skipEvent) { + return; + } + var oEvent = jQuery.Event("touchend"); + oEvent.originalEvent = { + query: oSearchParams.searchValue, + refreshButtonPressed: oSearchParams.refreshButtonPressed, + id: oSearchField.getId() + }; + oEvent.target = oSearchField; + oEvent.srcElement = oSearchField; + jQuery.extend(oEvent, oEvent.originalEvent); + + oSearchField.fireSearch(oEvent); + } + + Opa5.createPageObjects({ + onHome: { + actions: { + + iSelectItemFromTheProductList: function() { + return this.waitFor({ + controlType: "sap.m.ColumnListItem", + viewName: sViewName, + success: function(oPL) { + oPL[0].$().trigger("tap"); + Opa5.assert.ok(oPL, "First item got selected"); + }, + errorMessage: "The first item of the master list is not selected" + }); + + }, + + iGetTitleOfFirstItem: function() { + this.waitFor({ + controlType: "sap.m.Table", + viewName: sViewName, + matchers: new sap.ui.test.matchers.AggregationFilled({ + name: "items" + }), + success: function(oTable) { + this.getContext().sFirstProductTitle = "LCD";//oTable.getItems()[0].getTitle(); + }, + errorMessage: "Did not find product items" + }); + + }, + + iSearchForTheFirstObject: function() { + + this.waitFor({ + controlType: "sap.m.Table", + viewName: sViewName, + matchers: new sap.ui.test.matchers.AggregationFilled({ + name: "items" + }), + success: function(oTable) { + + sFirstObjectTitle = "LCD"//oTable.getItems()[0].getTitle(); + }, + errorMessage: "Did not find list items while trying to search for the first item." + }); + + return this.waitFor({ + id: "searchField", + viewName: sViewName, + success: function(oSearchField) { + enterSomethingInASearchField(oSearchField, { + searchValue: sFirstObjectTitle + }); + ok(true, "searched for " + sFirstObjectTitle); + }, + errorMessage: "Failed to find search field in Master view.'" + }); + } + + + + }, + + assertions: { + + iSeeProductListView: function() { + return this.waitFor({ + //id: "catalogTable", + controlType: "sap.m.Table", + viewName: sViewName, + matchers: new sap.ui.test.matchers.AggregationFilled({ + name: "items" + + }), + + success: function(oPL) { + Opa5.assert.ok(oPL, "Found the products list"); + }, + errorMessage: "Did not find the products list" + }); + }, + + iCheckIfItemSearchedIsMatchingOnMasterList: function() { + return this.waitFor({ + viewName: sViewName, + controlType: "sap.m.Table", + success: function(oList) { + var sFirstObjectTitleAfterSearch = "LCD";//oList.getItems()[0].getTitle(); + strictEqual(sFirstObjectTitleAfterSearch.trim(), sFirstObjectTitle.trim(), "Searched string is matching"); + }, + errorMessage: "Did not find the search list" + }); + } + + } + + } + }); + } +); \ No newline at end of file diff --git a/espm-cloud-web/src/main/webapp/webshop/test/integration/test.html b/espm-cloud-web/src/main/webapp/webshop/test/integration/test.html new file mode 100644 index 0000000..71bc4be --- /dev/null +++ b/espm-cloud-web/src/main/webapp/webshop/test/integration/test.html @@ -0,0 +1,25 @@ + + + ESPM OPA5 TEST + + + + + + +

ESPM OPA5 TEST

+ +

In this sample app for the testing tutorial we will test application functionality with OPA5

+ +

+These files can be used to run the application as a standalone application in the SAP Web IDE or after building and +serving with bower/grunt (expects a UI5 installation available at the server root, so this will not work without this +build and the grunt-based server). + +

For more documentation please read the UI5 Developer Guide.

+ + \ No newline at end of file diff --git a/espm-cloud-web/src/main/webapp/webshop/view/fragment/ReviewDialog.fragment.xml b/espm-cloud-web/src/main/webapp/webshop/view/fragment/ReviewDialog.fragment.xml index d646a62..c3a81ef 100644 --- a/espm-cloud-web/src/main/webapp/webshop/view/fragment/ReviewDialog.fragment.xml +++ b/espm-cloud-web/src/main/webapp/webshop/view/fragment/ReviewDialog.fragment.xml @@ -10,15 +10,15 @@ -