Academia.eduAcademia.edu
Development and Extension Guide SAP® Web Channel Experience Management 3.0 SP01 – Application-Specific Information Target Audience Technology consultants Development consultants System administrators at customer’s or host’s site Developers at customer‘s site Customer Document version 1.0 – October 2013 SAP AG Dietmar-Hopp-Allee 16 69190 Walldorf Germany T +49/18 05/34 34 24 F +49/18 05/34 34 20 www.sap.com © Copyright 2009 SAP AG. All rights reserved. Java is a registered trademark of Sun Microsystems, Inc. No part of this publication may be reproduced or transmitted in any JavaScript is a registered trademark of Sun Microsystems, Inc., used form or for any purpose without the express permission of SAP AG. under license for technology invented and implemented by Netscape. The information contained herein may be changed without prior notice. MaxDB is a trademark of MySQL AB, Sweden. Some software products marketed by SAP AG and its distributors SAP, R/3, xApps, xApp, SAP NetWeaver, Duet, PartnerEdge, contain proprietary software components of other software vendors. ByDesign, SAP Business ByDesign, and other SAP products and services mentioned herein as well as their respective logos are Microsoft, Windows, Outlook, and PowerPoint are registered trademarks or registered trademarks of SAP AG in Germany and in trademarks of Microsoft Corporation. several other countries all over the world. All other product and IBM, DB2, DB2 Universal Database, System i, System i5, System p, service names mentioned are the trademarks of their respective System p5, System x, System z, System z10, System z9, z10, z9, companies. Data contained in this document serves informational iSeries, pSeries, xSeries, zSeries, eServer, z/VM, z/OS, i5/OS, S/390, purposes only. National product specifications may vary. OS/390, OS/400, AS/400, S/390 Parallel Enterprise Server, PowerVM, Power Architecture, POWER6+, POWER6, POWER5+, POWER5, These materials are subject to change without notice. These materials POWER, OpenPower, PowerPC, BatchPipes, BladeCenter, System are provided by SAP AG and its affiliated companies ("SAP Group") Storage, GPFS, HACMP, RETAIN, DB2 Connect, RACF, Redbooks, for informational purposes only, without representation or warranty of OS/2, Parallel Sysplex, MVS/ESA, AIX, Intelligent Miner, any kind, and SAP Group shall not be liable for errors or omissions WebSphere, Netfinity, Tivoli and Informix are trademarks or with respect to the materials. The only warranties for SAP Group registered trademarks of IBM Corporation. products and services are those that are set forth in the express warranty statements accompanying such products and services, if any. Linux is the registered trademark of Linus Torvalds in the U.S. and Nothing herein should be construed as constituting an additional other countries. warranty. Adobe, the Adobe logo, Acrobat, PostScript, and Reader are either trademarks or registered trademarks of Adobe Systems Incorporated in Disclaimer the United States and/or other countries. Some components of this product are based on Java™. Any code change in these components may cause unpredictable Oracle is a registered trademark of Oracle Corporation. and severe malfunctions and is therefore expressively prohibited, as is any decompilation of these components. UNIX, X/Open, OSF/1, and Motif are registered trademarks of the Open Group. Any Java™ Source Code delivered with this product is Citrix, ICA, Program Neighborhood, MetaFrame, WinFrame, only to be used by SAP’s Support Services and may not be VideoFrame, and MultiWin are trademarks or registered trademarks of modified or altered in any way. Citrix Systems, Inc. Documentation in the SAP Service Marketplace HTML, XML, XHTML and W3C are trademarks or registered You can find this documentation at the following address: trademarks of W3C®, World Wide Web Consortium, Massachusetts http://service.sap.com/wec-inst Institute of Technology. D) Customer shall maintain the following copyright and permissions Terms for Included Open notices on STLport sources and its documentation unchanged: Copyright 2001 SAP AG Source Software E) The Customer may distribute original or modified STLport sources, This SAP software contains also the third party open source software provided that: products listed below. Please note that for these third party products o The conditions indicated in the above permissions notice are met; the following special terms and conditions shall apply. o The following copyright notices are retained when present, and 1. This software was developed using ANTLR. conditions provided in accompanying permission notices are met: 2. gSOAP Coypright 1994 Hewlett-Packard Part of the software embedded in this product is gSOAP software. Company Portions created by gSOAP are Copyright (C) 2001-2004 Robert A. Copyright 1996,97 Silicon Graphics van Engelen, Genivia inc. All Rights Reserved. Computer Systems Inc. THE SOFTWARE IN THIS PRODUCT WAS IN PART PROVIDED Copyright 1997 Moscow Center for BY GENIVIA INC AND ANY EXPRESS OR IMPLIED SPARC Technology. WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE Copyright 1999,2000 Boris Fomitchev IMPLIED WARRANTIES OF MERCHANTABILITY AND Copyright 2001 SAP AG FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. Permission to use, copy, modify, distribute and sell this software and IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY its documentation for any purposes is hereby granted without fee, DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR provided that the above copyright notice appear in all copies and that CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT both that copyright notice and this permission notice appear in LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR supporting documentation. Hewlett-Packard Company makes no SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS representations about the suitability of this software for any purpose. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY It is provided “as is” without express or implied warranty. OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, Permission to use, copy, modify, distribute and sell this software and OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) its documentation for any purpose is hereby granted without fee, ARISING IN ANY WAY OUT OF THE USE OF THIS provided that the above copyright notice appear in all copies and that SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF both that copyright notice and this permission notice appear in SUCH DAMAGE. supporting documentation. Silicon Graphics makes no representations 3. SAP License Agreement for STLport SAP License Agreement for about the suitability of this software for any purpose. It is provided “as STLPort between SAP Aktiengesellschaft Systems, Applications, is” without express or implied warranty. Products in Data Processing Neurottstrasse 16 69190 Walldorf, Permission to use, copy, modify, distribute and sell this software and Germany (hereinafter: SAP) and you (hereinafter: Customer) its documentation for any purposes is hereby granted without fee, a) Subject Matter of the Agreement provided that the above copyright notice appear in all copies and that A) SAP grants Customer a non-exclusive, non-transferrable, royalty- both that copyright notice and this permission notice appear in free license to use the STLport.org C++ library (STLport) and its supporting documentation. Moscow Center for SPARC makes no documentation without fee. representations about the suitability of this software for any purpose. It B) By downloading, using, or copying STLport or any portion thereof is provided “as is” without express or implied warranty. Customer agrees to abide by the intellectual property laws, and to all Boris Fomitchev makes no representations about the suitability of this of the terms and conditions of this Agreement. software for any purpose. This material is provided "as is", with C) The Customer may distribute binaries compiled with STLport absolutely no warranty expressed or implied. (whether original or modified) without any royalties or restrictions. Development and Extension Guide – Application-Specific Information Any use is at your own risk. Permission to use or copy this software C) In the case of Art. 4.2 above, SAP shall not be liable for indirect for any purpose is hereby granted without fee, provided the above damage, consequential damage caused by a defect or lost profit. notices are retained on all copies. D) SAP and the Customer agree that the typical foreseeable extent of Permission to modify the code and to distribute modified code is damage shall under no circumstances exceed EUR 5,000. granted, provided the above notices are retained, and a notice that the E) The Customer shall take adequate measures for the protection of code was modified is included with the above copyright notice. data and programs, in particular by making backup copies at the Permission to use, copy, modify, distribute and sell this software and minimum intervals recommended by SAP. SAP shall not be liable for its documentation for any purposes is hereby granted without fee, the loss of data and its recovery, notwithstanding the other limitations provided that the above copyright notice appear in all copies and that of the present Art. 4 if this loss could have been avoided by observing both that copyright notice and this permission notice appear in this obligation. supporting documentation. SAP makes no representations about the F) The exclusion or the limitation of claims in accordance with the suitability of this software for any purpose. It is provided with a present Art. 4 includes claims against employees or agents of SAP. limited warranty and liability as set forth in the License Agreement 4. Adobe Document Services Adobe, the Adobe logo, Acrobat, distributed with this copy. PostScript, and Reader are either registered trademarks or trademarks SAP offers this liability and warranty obligations only towards its of Adobe Systems Incorporated in the United States and / or other customers and only referring to its modifications. countries. For information on Third Party software delivered with b) Support and Maintenance SAP does not provide software Adobe document services and Adobe LiveCycle Designer, see SAP maintenance for the STLport. Software maintenance of the STLport Note 854621. therefore shall be not included. All other services shall be charged according to the rates for services quoted in the SAP List of Prices and Conditions and shall be subject to a separate contract. c) Exclusion of warranty As the STLport is transferred to the Customer on a loan basis and free of charge, SAP cannot guarantee that the STLport is error-free, without material defects or suitable for a specific application under third-party rights. Technical data, sales brochures, advertising text and quality descriptions produced by SAP do not indicate any assurance of particular attributes. d) Limited Liability A) Irrespective of the legal reasons, SAP shall only be liable for damage, including unauthorized operation, if this (i) can be compensated under the Product Liability Act or (ii) if caused due to gross negligence or intent by SAP or (iii) if based on the failure of a guaranteed attribute. B) If SAP is liable for gross negligence or intent caused by employees who are neither agents or managerial employees of SAP, the total liability for such damage and a maximum limit on the scope of any such damage shall depend on the extent to which its occurrence ought to have anticipated by SAP when concluding the contract, due to the circumstances known to it at that point in time representing a typical transfer of the software. Development and Extension Guide – Application-Specific Information Typographic Conventions Type Style Description Example Text Words or characters quoted from the screen. These include field names, screen titles, pushbuttons labels, menu names, menu paths, and menu options. Cross-references to other documentation Example text Emphasized words or phrases in body text, graphic titles, and table titles EXAMPLE TEXT Technical names of system objects. These include report names, program names, transaction codes, table names, and key concepts of a programming language when they are surrounded by body text, for example, SELECT and INCLUDE. Example text Output on the screen. This includes file and directory names and their paths, messages, names of variables and parameters, source text, and names of installation, upgrade and database tools. Example text Exact user entry. These are words or characters that you enter in the system exactly as they appear in the documentation. <Example text> Variable user entry. Angle brackets indicate that you replace these words and characters with appropriate entries to make entries in the system. EXAMPLE TEXT Keys on the keyboard, for example, F2 or ENTER. Icons Note Note text Caution Caution text Recommendation Recommendation text October 2013 5 Development and Extension Guide – Application-Specific Information Document History Before you start the implementation, make sure you have the latest version of this document. You can find the latest version at the following location: http://service.sap.com/wec-inst or http://service.sap.com/instguides The following table provides an overview of the most important document changes: Version Date Description 1.0 October 2013 Initial version 6 October 2013 Development and Extension Guide – Application-Specific Information Table of Contents 1 Introduction .......................................................................................................................................................... 10 1.1 About This Document................................................................................................................................. 10 1.2 Naming Conventions .................................................................................................................................. 10 1.3 Introduction to Application-Specific Information .......................................................................................... 11 1.4 Web Channel Builder Modules ................................................................................................................... 12 1.4.1 Common Settings Module (Namespace sap-wcf) ......................................................................... 12 1.4.2 Common Settings Module (Namespace sap) ............................................................................... 13 1.4.3 User Management Module........................................................................................................... 14 1.4.4 Payment Methods Module ........................................................................................................... 16 1.4.5 Sales Transactions Module.......................................................................................................... 17 1.4.6 Checkout Module......................................................................................................................... 18 1.4.7 Wish Lists Module ....................................................................................................................... 20 1.4.8 Trade Articles Module .................................................................................................................. 20 1.4.9 In-Store Pickup Module ............................................................................................................... 22 1.4.10 Store Locator Module .................................................................................................................. 23 1.4.11 Main Module (main) ..................................................................................................................... 24 1.4.12 Content Management Module ...................................................................................................... 26 1.4.13 My Support Module ..................................................................................................................... 26 1.4.14 My Account Module ..................................................................................................................... 27 1.4.15 Shopping Templates Module ....................................................................................................... 27 1.4.16 Product Views Main Module......................................................................................................... 29 1.5 Application Plug-Ins ................................................................................................................................... 31 1.5.1 Sales Transactions and Wish Lists Plug-Ins ................................................................................. 34 2 Generic Topics ..................................................................................................................................................... 36 2.1 Application Modules ................................................................................................................................... 36 2.1.1 Creating and Integrating New Modules into the Application .......................................................... 36 2.1.2 Integrating the New Module into the Common Application Infrastructure ...................................... 38 2.2 Currency Converters .................................................................................................................................. 42 2.3 Central Header and Footer......................................................................................................................... 44 2.4 JavaScript for Web Analytics ...................................................................................................................... 46 2.5 Country-Specific Address Formats ............................................................................................................. 48 2.5.1 Setting Up the SAP CRM or SAP ERP Back End ......................................................................... 48 2.5.2 Creating New Views for New Address Display ............................................................................. 48 2.6 Store Locator - Google Maps ..................................................................................................................... 50 2.6.1 Store Locator............................................................................................................................... 50 2.6.2 Graphical Map Interface .............................................................................................................. 51 2.7 Store Locator - NAVTEQ Maps .................................................................................................................. 56 2.8 CSS-Only Changes to Configuration UI (Status Icons) ............................................................................... 58 3 Product Catalog ................................................................................................................................................... 61 3.1 Transfer of Additional Fields from MDM to Product Catalog ........................................................................ 61 3.2 Transfer of Additional Fields from CRM to MDM ......................................................................................... 64 3.2.1 Introduction ................................................................................................................................. 64 3.2.2 Steps on CRM Side ..................................................................................................................... 65 3.2.3 Steps on MDM Side..................................................................................................................... 72 3.3 Product View Modules................................................................................................................................ 76 3.3.1 Creating an Additional MDM Attribute for Product View ................................................................ 76 3.3.2 Creating an Additional User Context for Product View.................................................................. 82 4 Product Configuration........................................................................................................................................... 83 4.1 Custom UI Rendering for Characteristics on Configuration UI ..................................................................... 83 4.1.1 Adding a Custom Mapper for the Configuration UI ....................................................................... 83 4.1.2 Registering a New UI Type .......................................................................................................... 84 October 2013 7 Development and Extension Guide – Application-Specific Information 4.1.3 Adding the Custom XHTML Fragment ......................................................................................... 85 4.2Shopping Cart Summary with Pricing on Configuration UI .......................................................................... 86 4.2.1 Changing the Layout of the Configuration UI from 2-Column-Navigation to 2-Column-Sidebar ..... 87 4.2.2 Including the Mini Cart Preview in the Sidebar Using Module Interfacing ...................................... 88 4.2.3 Adapting the Re-Render IDs ........................................................................................................ 88 4.3 Removal of “Not Specified” Option on Configuration UI .............................................................................. 90 4.4 Reference Characteristics .......................................................................................................................... 91 5 Shopping Cart and Order ..................................................................................................................................... 97 5.1 Custom Attributes ...................................................................................................................................... 97 5.1.1 Enhancing Fields in the Back End................................................................................................ 97 5.1.2 Displaying Custom Fields on the UI ............................................................................................. 98 5.1.3 Adding Resource Keys for New Labels on the Web Shop UI ...................................................... 101 5.1.4 Reading Custom Fields from the Back End ................................................................................ 101 5.1.5 Writing Custom Fields to the Back End ...................................................................................... 103 5.1.6 Extending the Checkout UI ........................................................................................................ 104 5.2 Additional Fields Read from ERP SD via LO-API ...................................................................................... 107 5.2.1 Extending Module and Registering Extensions........................................................................... 107 5.2.2 Reading Substitution Reason and Attaching it to New Message ................................................. 108 5.3 Shopping Cart - User Interface ................................................................................................................. 110 5.3.1 Adding a New Field Using the AET ............................................................................................ 110 5.3.2 Adding A New Field Using Java ................................................................................................. 117 5.4 Shopping Cart - J2EE Data Persistence ................................................................................................... 122 5.4.1 Creating Class Representing the Object to be Persisted (Serializable) ....................................... 122 5.4.2 Creating View Component ......................................................................................................... 123 5.4.3 Creating View Component Handler ............................................................................................ 125 5.4.4 Registering View Component Handler ....................................................................................... 128 5.4.5 Overwriting Surrounding Component and Including New Component ......................................... 129 5.5 IPC Pricing............................................................................................................................................... 131 5.5.1 Standard Attributes for IPC Pricing (SAP CRM) ......................................................................... 131 5.5.2 Standard Attributes for IPC Pricing (SAP ERP) .......................................................................... 132 5.5.3 Extension Example .................................................................................................................... 133 5.6 Order Search (SAP ERP) ......................................................................................................................... 136 5.6.1 New Search Criteria .................................................................................................................. 136 5.6.2 Search Results for New Search Criteria ..................................................................................... 137 5.6.3 Adding New Fields to the Result List .......................................................................................... 139 5.6.4 Using the New Definition of the Search Description.................................................................... 141 5.7 Display of Schedule Lines (SAP ERP) ...................................................................................................... 142 5.8 Reading of Additional Attributes (SAP CRM) ............................................................................................ 144 5.9 Delivery Types and Requested Delivery Dates ......................................................................................... 148 5.9.1 Adapting BO Layer to Set Requested Delivery Date................................................................... 148 5.9.2 Adapting UI Layer to Set Delivery Type Depending on Requested Delivery Date ....................... 149 5.10 Proposed Shopping Templates ................................................................................................................ 151 5.11 Document Converter Manager ................................................................................................................. 159 5.11.1 Extending the Module Settings .................................................................................................. 159 5.11.2 Implementing and Registering a New Convertible ...................................................................... 161 5.11.3 Implementing the UI Part ........................................................................................................... 162 5.12 Mapping of Back-End Messages to UI Messages ..................................................................................... 163 5.13 Additional Pricing in Cart or Order ............................................................................................................ 164 5.14 In-Store Pickup ........................................................................................................................................ 165 6 Payment Process ............................................................................................................................................... 169 6.1 Payment Service Providers ...................................................................................................................... 169 6.1.1 Architecture Overview................................................................................................................ 170 6.1.2 Web Service Integration (PayPal Example)................................................................................ 171 6.1.3 SAP ERP E-Commerce ............................................................................................................. 229 6.1.4 SAP CRM Replication Scenario ................................................................................................. 259 8 October 2013 Development and Extension Guide – Application-Specific Information 6.1.5 Order-Related SAP CRM Billing................................................................................................. 306 6.1.6 Delivery-Related SAP CRM Billing ............................................................................................. 308 6.1.7 Extension Points........................................................................................................................ 310 6.2 Payment Card Authorization (SAP CRM).................................................................................................. 311 6.3 Integration of E-Payment Processing Service for Credit Card Tokenization............................................... 312 7 Web Services..................................................................................................................................................... 314 7.1 Web Service Entity "Companies" .............................................................................................................. 314 7.2 Web Service Entity "Consumer" ............................................................................................................... 316 7.2.1 Registration Request via Web Service Consumer ...................................................................... 316 7.2.2 Reading Data via Web Service Consumer ................................................................................. 319 7.2.3 Updating Data via Web Service Consumer ................................................................................ 320 7.3 Web Service "SalesOrderItemScheduleLines" .......................................................................................... 322 October 2013 9 Development and Extension Guide – Application-Specific Information 1 Introduction The information in this guide is confidential and proprietary to SAP and may not be disclosed without the permission of SAP. This guide is not subject to your license agreement or any other service or subscription agreement with SAP. SAP has no obligation to pursue any course of business outlined in this document or any related guide, or to develop or release any functionality mentioned therein. This document, or any related guide about SAP’s strategy and possible future developments, directions, and functionality of products and/or platforms, are all subject to change and may be changed by SAP at any time for any reason without notice. The information in this document is not a commitment, promise, or legal obligation to deliver any material, code, or functionality. This document is provided without a warranty of any kind, either express or implied, including but not limited to, the implied warranties of merchantability, fitness for a particular purpose, or non-infringement. This document is for informational purposes and may not be incorporated into a contract. SAP assumes no responsibility for errors or omissions in this document, except if such damages were caused by SAP intentionally or grossly negligent. All forward-looking statements are subject to various risks and uncertainties that could cause actual results to differ materially from expectations. Readers are cautioned not to place undue reliance on these forward-looking statements, which speak only as of their dates, and they should not be relied upon in making purchasing decisions. SAP AG – Walldorf (Germany) 1.1 About This Document The Development and Extension Guide for SAP Web Channel Experience Management is written for the following main target groups: Technology consultants Development consultants System administrators at customer’s or host’s site Developers at customer‘s site This document is mainly intended for the above-mentioned target groups who have basic Java skills, who know SAP CRM and SAP ERP, and who want to set up their own local development environment in order to extend and modify the Web Channel application to their needs. The Development and Extension Guide consists of the following main sections: Introduction Generic Topics Product Catalog Product Configuration Shopping Cart and Order Payment Process Trade 1.2 Naming Conventions In this documentation, the following naming conventions apply: Java Server Faces (JSF) Expression Language expressions (EL expressions) Development component (DC) Software component (SC) Design Time Repository (DTR) Component Build Service (CBS) 10 October 2013 Development and Extension Guide – Application-Specific Information Change Management Service (CMS) Java Runtime Environment (JRE) SAP Web Channel Experience Management (WCEM) SAP NetWeaver Developer Studio (NWDS) SAP NetWeaver Development Infrastructure (NWDI) Integrated Development Environment (IDE) System Landscape Directory (SLD) 1.3 Introduction to Application-Specific Information You can use the information and examples provided in this part of the guide to further develop and extend applications of SAP Web Channel Experience Management. For more information about development and extension, see the Development and Extension Guide: Generic Information for SAP Web Channel Experience Management on SAP Service Marketplace at http://service.sap.com/wec-inst. October 2013 11 Development and Extension Guide – Application-Specific Information 1.4 Web Channel Builder Modules The following table explains the Web Channel Builder modules delivered with SAP Web Channel Experience Management: Module ID Namespace Common Settings com.sap.common sap-wcf Common Settings com.sap.common sap User Management user sap Payment Methods payment sap Sales Transactions salestransactions sap Checkout checkout sap Wish Lists wishlist sap Trade Articles article sap In-Store Pickup instore sap Store Locator storelocator sap Main main sap Content Management contentmanagement sap My Support mysupport sap My Account myaccounts sap Shopping Templates shoppingtemplates sap Product Views productviews sap 1.4.1 Common Settings Module (Namespace sap-wcf) Introduction The Common Settings module (namespace sap-wcf) of Web Channel Builder provides reusable functionality and services that can be used by all other modules. For example, this module provides the generic search for the dynamic UI and the process flow framework. Detailed Description This module provides the following generic functionality: Generic search framework Help value search Dynamic UI framework Process flow Default layouts Default content for header view Application list page Admin pages Required Module Interfaces None 12 October 2013 Development and Extension Guide – Application-Specific Information Exposed Module Interfaces Business Object Interfaces com.sap.wcf.GenericSearchProvider Provides access to the generic search framework. The interface allows the reuse of generic search while providing a UI for the results. UI Interfaces View Components com.sap.wcf.GS.SimpleSearch/SimpleSearch Simple search com.sap.wcf.GS.AdvancedSearch/AdvancedSearchView Advanced search com.sap.wcf.ProcessFlow/processFlow Process flow entry view component com.sap.wcf.ProcessFlow/processFlowHorizontalHost Host for horizontal view com.sap.wcf.ProcessFlow/processFlowVerticalHost Host for vertical view com.sap.wcf.Menu/menu Dynamic menu view component controlled via menu configuration com.sap.wcf.contentHeaderInfo/contentHeaderInfo Generic content header view component that dynamically provides the breadcrumbs com.sap.wcf.headMetadata/headMetadata View component to provide metadata from the different views displayed to the header Layouts com.sap.wcf.Layouts/1column One-column layout com.sap.wcf.Layouts/2columnNavigation Two-column layout with navigation bar com.sap.wcf.Layouts/2columnSidebar Two-column layout with side bar com.sap.wcf.Layouts/3column Three-column layout com.sap.wcf.Layouts/1column One-column layout com.sap.wcf.Layouts/baseHeaderFooterLayout Base page layout with header and footer 1.4.2 Common Settings Module (Namespace sap) Introduction The Common Settings module (namespace sap) of Web Channel Builder provides common application functionality such as conversion, validation, and common application Customizing. Moreover, it contains some re-use functionality. This module is always part of the application. Do not change the namespace in Web Channel Builder to sap-wcf, because then only the sap-wcf part of this module is available. October 2013 13 Development and Extension Guide – Application-Specific Information Note If you extend this module in another namespace, ensure that the type is still system. Check attribute moduleType in metadata.xml. Detailed Description The following functions are available: Access to common customizing (for example, sales area) Can be access through BO access object CommonConfigurationAccess Conversion for units, dates, and currencies Available on BO level through CommonConverterAccess and also on UI level through different JSF converters (wecCurrency, wecUnit, and wecUnitID). Available converters: ID Description wecCurrency Converts a currency in BigDecimal into a String and vice versa. Re-uses standard JSF converter for currency symbol display, but also takes Customizing for decimal places into account. wecUnit Converts a unit amout in BigDecimal into a String and vice versa. Takes Customizing for decimal places into account. wecUnitID Converts a language-independent SAP unit key (for example, ST) into a language-dependent key (for example, PC in English). Required Module Interfaces None Exposed Module Interfaces Business Object Interfaces Interface ID Description com.sap.common.Configuration Acess to common configuration (for example, currency or sales area) com.sap.common.Converter Access to conversion for currencies and units com.sap.common.Attachment Access to attachment functionality 1.4.3 User Management Module Introduction The User Management module of Web Channel Builder provides functions that are related to the logon and registration of users. Detailed Description This module provides the following generic functionality: Log on to shop (with different logon types) Registration of new users Support for forgotten passwords Support for forgotten user IDs Change passwords Change user data 14 October 2013 Development and Extension Guide – Application-Specific Information Personalization Required Module Interfaces com.sap.common.Configuration com.sap.common.Converter Optional Module Interfaces com.sap.sales.Order com.sap.wishlist.GeneralInfo com.sap.PaymentMasterDataAccess com.sap.common.KnowledgeManagement com.sap.myAccounts com.sap.mySupport com.sap.main com.sap.sales.CheckoutCallback Exposed Module Interfaces Business Object Interfaces com.sap.user.UserDataProvider Requesting user data information com.sap.user.UserFunctionProvider Functions available to the users com.sap.user.BusinessPartner Business partners com.sap.user.UserRegistrationPlugIn Plug-in for registration page For more information, see Application Plug-Ins. UI Interfaces View Components com.sap.user.LoginRegisterAnchorView/mainpageLoginRegisterAnchorView Logon link and status used in the header com.sap.user.LoginInfoView/mainpageLoginInfoView User name displayed in the header com.sap.user.LoginRegistrationView/loginRegistrationView User login and registration to be used on your own page (for example, process flow). The view itself has no form tag to submit the data. com.sap.user.PersonalizationAnchorView/mainpagePersonalizationAnchorView Personalization link used in the header com.sap.user.AddressViews/addressSelector Including address views com.sap.user.AddressViews/singleAddress Included address views com.sap.user.AddressViews/singleAddressReadonly Included address views com.sap.user.ContactViews/contactInformation Included contact information views com.sap.user.ContactViews/contactInformationReadonly Included contact information views com.sap.user.ContactViews/companyCommunData Included contact information views October 2013 15 Development and Extension Guide – Application-Specific Information com.sap.user.ContactViews/companyGeneralData Included contact information views com.sap.user.ContactViews/contactCommunData Included contact information views com.sap.user.ContactViews/contactGeneralData Included contact information views com.sap.user.RegisterView Plug-in for views on registration page com.sap.user.RegisterConfirmationView Plug-in for views on registration confirmation page For more information, see Application Plug-Ins. UI Objects com.sap.user.locking/accountDataLockProvider Used to lock the user Navigation Targets com.sap.user.AccountViews/myAccountAccountDetailsB2C Navigation for the account details view com.sap.user.AccountViews/myAccountContactDetailsForBreadcrumb Navigation for the contact details view com.sap.user.Login/toUserLogin Navigation to the user login view 1.4.4 Payment Methods Module Introduction The Payment Methods module of Web Channel Builder provides functionality to offer Web shop customers different payment methods during checkout. Detailed Description The following table explains the payment methods supported by each back end: Payment Method Back End Invoice SAP CRM and SAP ERP Credit cards SAP CRM and SAP ERP Cash on delivery SAP CRM Payment service providers (using BAdI) SAP CRM and SAP ERP Required Module Interfaces sap.wcf Optional Module Interfaces com.sap.sales.Order com.sap.user.BusinessPartner com.sap.myAccounts com.sap.sales.Checkout com.sap.user.locking 16 October 2013 Development and Extension Guide – Application-Specific Information Exposed Module Interfaces None Business Object Interfaces None UI Interfaces View Components None Navigation Targets com.sap.sales.Checkout/preConfirmation 1.4.5 Sales Transactions Module Introduction The Sales Transactions module in Web Channel Builder provides functionality to run business-to-consumer (B2C) or business-to-business (B2B) selling processes on the Internet (that is, the consumer and contact scenarios, respectively). Detailed Description This module enables Web shop customers to do the following: View the shopping cart and add products directly to the shopping cart Add products from the product catalog, wish list, or existing order to the shopping cart View the shopping cart preview after adding products to the shopping cart Navigate to the checkout (if the Checkout module of Web Channel Builder is available) Required Module Interfaces com.sap.main com.sap.wcf.Layouts com.sap.common.SearchFilter com.sap.common.Configuration com.sap.common.Converter com.sap.user.UserDataProvider com.sap.user.UserFunctionProvider com.sap.user.BusinessPartner com.sap.user.Login com.sap.ipc.IPCClient Optional Module Interfaces com.sap.PaymentDataAccess com.sap.PaymentCommunicationAccess com.sap.sales.CheckoutOrder com.sap.sales.CheckoutLocking com.sap.emkt.FreeGoods com.sap.common.Catalog com.sap.common.Catalog.DetailPage com.sap.marketing.Campaign com.sap.common.ProductRecommend com.sap.wishlist.WishListProductProvider October 2013 17 Development and Extension Guide – Application-Specific Information com.sap.common.Catalog.ContinueShoppingView com.sap.productAvailabilityViews Exposed Module Interfaces Business Object Interfaces com.sap.sales.Order Interface for the sales order com.sap.sales.Basket Interface for the cart com.sap.sales.BasketProductProvider Interface for adding a product to the shopping cart com.sap.sales.Campaign Interface for the interaction with a campaign For information on code plug-ins, see Sales Transactions and Wish Lists Plug-Ins. UI Interfaces View Components com.sap.sales.BasketPreview/addToBasket Interface for adding products to a cart minibasketoverlayIncl Interface for the minibasket used in the header com.sap.sales.GeneralInfo/trackOrdersIncl Interface for the My Orders link in the header orderitemsearch Interface for including an item search Objects com.sap.sales.GeneralInfo/salesDocBeanProvider Provides access to the sales document bean com.sap.sales.SalesLocking/salesTransactionsLockProvider Provides lock services for the sales transaction module com.sap.sales.Checkout/pageIsDisplayedMediator Used to find out the currently displayed page (shopping cart or checkout page) For information on code plug-ins, see Sales Transactions and Wish Lists Plug-Ins. Navigation Targets com.sap.sales.Checkout/orderConfirmation com.sap.sales.Checkout/preConfirmation com.sap.sales.Checkout/order com.sap.sales.Checkout/basket 1.4.6 Checkout Module Introduction The Checkout module in Web Channel Builder is important when Web shop customers order products. Checkout aggregates all the information necessary for completing the ordering process, such as the following: Bill-to and ship-to addresses Payment methods A summary of ordered products and costs 18 October 2013 Development and Extension Guide – Application-Specific Information Detailed Description When this module is part of the Web shop configuration, you can configure the following in Web Channel Builder for the Web shop: URL for terms and conditions Delivery types allowed Checkout profile group used When you add the Checkout module to the configuration, the system adds the Checkout Process Configuration module (com.sap.checkout.processconfig). The Checkout Process Configuration module holds the configuration of the checkout process in XML format. This configuration contains information about the checkout step and checkout step elements the Web shop customer uses while performing the checkout (for example, the shipping details checkout step might consist of the following elements: ship-to address and delivery type). Required Module Interfaces Check the metadata.xml located in the md part of the module. com.sap.sales.Checkout com.sap.sales.SalesLocking com.sap.user.locking com.sap.common.Configuration com.sap.common.Converter com.sap.PaymentDataAccess com.sap.user.LoginRegistrationView com.sap.sales.CheckoutProcessConfig Exposed Module Interfaces com.sap.sales.CheckoutOrder Used in the Sales Transactions module to show views (for example, the shipping collapsed view and the billing collapsed view) from checkout on the order confirmation page and for navigating to checkout. com.sap.sales.CheckoutConfiguration Used from the Main module to get access to the general terms and conditions (GTC) URL. A link to the GTC is displayed on a view belonging to the Main module. Generally, it is possible to get access to other checkout configuration information (such as enabled delivery types) by using this interface. com.sap.sales.CheckoutCallback Used from the Users module to enable the login of users in checkout when Web shop customers choose the Continue pushbutton in the Personal Data checkout step. com.sap.sales.CheckoutLocking Used from the Sales Transactions module in the context of multiple browser support. This module interface exposes a UI object that allows for invalidating a checkout process if changes in the shopping cart have occurred in another browser window or tab in the same session. com.sap.checkout.FilterPaymentMethodsPlugIn Used to filter the payment methods that the system displays in checkout. UI Interfaces View Components Check the ui-repository.xml file of the ui part of the module. com.sap.sales.CheckoutOrder/confirmationIncl Used from the Sales Transactions module on the order confirmation page Layouts Check the ui-repository.xml file of the ui part of the module. October 2013 19 Development and Extension Guide – Application-Specific Information 1.4.7 Wish Lists Module Introduction You make settings in the Wish List module of Web Channel Builder to enable Web shop customers to make persistent wish lists for Web shops. Web shop customers can use wish lists to remind themselves to purchase products at a later time. Detailed Description This module enables Web shop customers to do the following: Display their wish lists (logged-in user) Add products from the product catalog to their wish lists (if the Product Catalog module is available) Add products from their wish lists to the shopping cart (if the Sales Transactions module is available) Required Module Interfaces com.sap.main com.sap.wcf.Layouts com.sap.user.Login Optional Module Interfaces com.sap.myAccounts com.sap.common.Catalog com.sap.common.Catalog.DetailPage com.sap.common.Catalog.DetailOtherFunctions com.sap.common.Catalog.BlockViewOtherFunctions com.sap.common.Catalog.ListViewOtherFunctions com.sap.marketing.ProductRecommend.OtherFunctions com.sap.productAvailabilityViews com.sap.sales.CheckoutLocking com.sap.sales.SalesLocking com.sap.sales.Basket Exposed Module Interfaces Business Object Interfaces Code plug-ins For more information, see Sales Transactions and Wish Lists Plug-Ins. UI Interfaces View Components com.sap.wishlist.GeneralInfo/MyWishListHeaderView For more information, see Sales Transactions and Wish Lists Plug-Ins. Objects None 1.4.8 Trade Articles Module Introduction You make settings in the Trade Articles module of Web Channel Builder to enable Web shop customers to order variants of generic articles. 20 October 2013 Development and Extension Guide – Application-Specific Information Detailed Description This module contains implementations of extensions offered by other modules, mainly the Product Catalog module. It allows a proper handling of generic articles on the browsing page and details page and in the simple search. Generic articles are displayed on a dedicated product details page. Generic article characteristics can be used for the filter-based navigation of the product catalog. The usage of generic articles in other modules is controlled as follows: Sales Transactions Only variants can be added to the shopping cart. Wish Lists Only variants can be added to wish lists. Shopping Templates Only variants can be added to shopping templates. Customer Interaction Ratings can only be entered for generic articles. Product Recommendations Free goods must be defined individually for variants. In addition, it is possible to define free goods for generic articles displayed on the browsing page. Product Availability An availability check is only possible for variants. In-Store Pickup In-store handling is only possible for variants. This module can only be used in conjunction with the SAP CRM back end connected to SAP Retail (SAP ERP). Required Module Interfaces com.sap.common.Catalog com.sap.common.Catalog.PriceView com.sap.common.Catalog.DetailPage com.sap.user.UserDataProvider Exposed module interfaces Business Object Interfaces com.sap.wec.trade.Article Provides access to article specific objects, such as the following: o Configuration o Article explorer, public interface for accessing article-specifc information of a catalog item o Article catalog, provides additional functionality for articles compared to the core catalog UI Interfaces View Components com.sap.wec.trade.BlockViewOtherFunctions View plug-in; the counterpart to com.sap.common.Catalog.BlockViewOtherFunctions for a tile of the block view on the catalog browsing page in case a generic article is displayed com.sap.wec.trade.ListViewOtherFunctions View plug-in; counterpart to com.sap.common.Catalog.ListViewOtherFunctions for a row of the list view on the catalog browsing page in case a generic article is displayed Layouts None October 2013 21 Development and Extension Guide – Application-Specific Information 1.4.9 In-Store Pickup Module Introduction You make settings in the In-Store Pickup module of Web Channel Builder to enable Web shop customers to order products in the Web shop and collect their purchases from conventional retail stores. Detailed Description In addition to buying products online in the Web shop for delivery, Web shop customers can order products for pickup in selected stores. Web shop customers select stores using the store locator (note there is a Store Locator module in Web Channel Builder), which includes a distance search that returns the nearest stores. The system shows product availability for each store found. The back end supports a reservation workflow which allows for feedback to Web shop customers that ordered products are ready for pickup or could not be reserved. There is also a variant available that only shows product availability in the stores found (without the possibility to actually order the product). If the desired product is available in a store, Web shop customers find the necessary contact data (address, telephone, e-mail address, and so on) to take further actions. For example, they can call the store and agree to reserve products for pickup later. Required Module Interfaces com.sap.storelocator.StoreSearchManager Used to retrieve the StoreSearch object, which provides the list of found stores com.sap.storelocator.textualSearch Used to include the store search UI on the in-store pickup page com.sap.common.Catalog.DetailMiddleBelowAddToCart Used to integrate into to the product details UI (add a link showing availability in stores) com.sap.common.Catalog Used to use the catalog item business object and to register an extension to read additional MDM data (field WECMDM_INSTORE_PICKUP_MODE) com.sap.user.BusinessPartner Used to use the user business object com.sap.common.Configuration Used to read the sales organization that is configured for the Web shop com.sap.common.Catalog.PriceView Used to integrate the price view of the catalog on the in-store pickup page com.sap.sales.Basket Used to perform an "add-to-cart" on the shopping cart business object com.sap.sales.Order Used to integrate in-store pickup availability and store address on item level on the My Orders page com.sap.wec.trade.Article Used to use the article business objects com.sap.main Used to implement breadcrumbs com.sap.wcf.Layouts Used to provide the in-store pickup page com.sap.wcf.Menu Used to integrate the top-level menu of the store page Exposed Module Interfaces Business Object Interfaces com.sap.wec.trade.instore.businessobject.intf.AvailabilityCheckBOAccess Provides access to functionality to read availablilty information for stores from the back end UI Interfaces 22 October 2013 Development and Extension Guide – Application-Specific Information None View Components instore-availability-link.xhtml Implements the link for checking availability in stores on the product details page instore-pickup-link.xhtml Implements the link for in-store pickup on the product details page instore.xhtml Implements the whole content of the in-store pickup page basketRichUIAvailability.xhtml Implements the rendering of the in-store pickup information and store address of an in-store pickup item on the extended UI of the shopping cart basketLeanUIAvailability.xhtml Implements the rendering of the in-store pickup information and store address of an in-store pickup item on the standard UI of the shopping cart orderRichUIDelivery.xhtml Implements the rendering of the in-store pickup information and store address of an in-store pickup item in the checkout and in orders Layouts The standard column layout is used. 1.4.10 Store Locator Module Introduction You make settings in the Store Locator module of Web Channel Builder to enable Web shop customers to search for stores (including service centers) by using the store locator in the Web shop. Detailed Description This module provides the following features: Textual search for stores Possibility to integrate a graphical map Fully functional example integration of Google Maps Two search modes o Database-like search (default) o Distance search using a geo-coding service to find nearby stores Required Module Interfaces com.sap.user.UserDataProvider Used to determine whether a user is logged on com.sap.user.BusinessPartner Used to default the search fields according to the user's address (if logged on) com.sap.common.Configuration Used to read the sales area information of the common configuration com.sap.wcf.Layouts Used to reference the standard layout Exposed Module Interfaces Business Object Interfaces com.sap.wec.app.common.mc.module.storelocator.businessobject.interf.StoreSearchManager Provides access to functionality to search for stores October 2013 23 Development and Extension Guide – Application-Specific Information com.sap.wec.app.common.mc.module.storelocator.businessobject.interf.StoreSearchConfiguration Provides access to the configuration of store locator UI Interfaces com.sap.storelocator.textualSearch Enables reuse of the search part of the textual store locator search. Also used in the In-Store Pickup module of Web Channel Builder. com.sap.storelocator.openingTimes Enables reuse of the business hours of store locator. Also used in the In-Store Pickup module of Web Channel Builder. View Components graphical-map.xhtml Contains the graphical map. graphical-result.xhtml Contains the store result list in the graphical store locator. graphical-search.xhtml Contains the search fields in the graphical store locator. graphical-store-detail.xhtml Contains the detail view of a store in the graphical map. header.xhtml Header of the store locator (for both graphical and textual store locator) main-page-link.xhtml Link for the store locator on the main page opening-times-overlay.xhtml Business hours overlay in the textual store locator opening-times-table.xhtml Business hours table within the graphical store locator parent.xhtml Parent view containing search and result view (for both graphical and textual store locator) textual-result.xhtml Contains the store result list of the textual store locator. textual-search.xhtml Contains the search fields and buttons of the textual store locator. Layouts The standard column layout is used. 1.4.11 Main Module (main) Introduction The Main module of Web Channel Builder module provides a page with the header and footer used throughout the application. It also contains the configuration files for application menu and breadcrumb handling. If this part of the application infrastructure needs to be changed, you must extend the Main module. Note If you extend this module in a different namespace, ensure that it is still flagged as main module. See attribute mainModule in the metadata.xml file. Required Module Interfaces No required interfaces. The Main module consumes other application module's interfaces softly. This means that if those interfaces are available, the system renders the respective header entries or menu links. 24 October 2013 Development and Extension Guide – Application-Specific Information Exposed Module Interfaces Business Object Interfaces None UI Interfaces View Components Module interface Include ID Description com.sap.main header Header area of the WCEM application. Includes menu, breadcrumb trail, certain links, and functions for searching, cart navigation, and checkout. com.sap.main footer Footer area of the WCEM application. Includes links to pages like About Us. Pages Module interface Page ID Description com.sap.main basePage Common page, which describes the overall layout of a WCEM page (besides the content area, which is controlled by layouts in the system module). Its layout is defined through layout baseLayout. To create another base page, the Main module needs to be extended or replaced. The corresponding layout then also needs to be provided. com.sap.main myAccountHomePage Page that contains the My Account pushbutton on the left-hand side of the screen com.sap.main mySupportHomePage Page that contains the Service And Support pushbutton on the left-hand side of the screen Navigation Targets Module interface Navigation Target Description com.sap.main toCustomerService Forwards the service page, which by default just provides a static text. If desired, more content can be included using an extension. com.sap.main actionShowAdvancedSearchView Forwards to the Product Catalog module through interface com.sap.common.Catalog.Naviga tionView. com.sap.main toMyAccount Forwards to myAccountHomePage to display the My Account navigation area on the left-hand side of the screen. com.sap.main toMySupport Forwards to mySupportHomePage to display the My Support navigation area on the left-hand side of the screen. October 2013 25 Development and Extension Guide – Application-Specific Information 1.4.12 Content Management Module Introduction You make settings in the Content Management module of Web Channel Builder to integrate external content into the Web shop. Detailed Description This module provides an interface to integrate external Web content. Required Module Interfaces com.sap.wcf.Layouts Optional Module Interfaces com.sap.user.Login com.sap.common.Catalog.SideBarView Exposed Module Interfaces UI Interfaces View Components com.sap.contentmanagement.ui/externalContextView com.sap.common.Catalog.SideBarView/plugIn com.sap.user.RegisterView/plugIn For more information about plug-ins, see Application Plug-Ins . Layouts None 1.4.13 My Support Module Introduction You make settings in the My Support module of Web Channel Builder to provide a menu with a hierarchy structure for support in the Web shop. Detailed Description You can make settings to show menu headings in the Web shop for the following: Service requests Complaints and returns Product registration Knowledge base Required Module Interfaces None Exposed Module Interfaces Business Object Interfaces com.sap.mySupport.config.Anchor Anchor for Web Channel Builder usage reference UI Interfaces View Components 26 October 2013 Development and Extension Guide – Application-Specific Information com.sap.mySupport/tree Used to show menu tree on the left-hand side Layouts None 1.4.14 My Account Module Introduction You make settings in the My Account module of Web Channel Builder to add, remove, and arrange menu headings and menu options in the navigation area of My Account. Detailed Description You can add menu headings in the My Account module for the following: Transactions Settings Personalization Products and service contracts Preferences Required Module Interfaces com.sap.wcf.UserCore Exposed Module Interfaces Business Object Interfaces com.sap.myAccount.config.Anchor Anchor for Web Channel Builder usage reference UI Interfaces View Components com.sap.myAccounts/tree Used to show menu tree on the left-hand side com.sap.myAccounts/content Default content view Layouts None 1.4.15 Shopping Templates Module Introduction You make settings in the Shopping Templates module of Web Channel Builder to enable Web shop customers to save lists of frequently ordered products, in shopping templates. Detailed Description This module enables Web shop customers to do the following: Create, copy, change, and remove shopping templates Add products from the product catalog to their shopping templates (if the Product Catalog module is available) Add products from the shopping cart or from orders to their shopping templates (if the Sales Transactions module is available) October 2013 27 Development and Extension Guide – Application-Specific Information Add products from the shopping template to the shopping cart, and order the products (if the Sales Transactions and Checkout modules are available) Required Module Interfaces com.sap.wcf.Layouts Used to provide the shopping templates page com.sap.main Used to implement the breadcrumb logic com.sap.user.Login Used to redirect to the logon page com.sap.user.UserDataProvider Used to check whether a known user is logged on com.sap.user.UserFunctionProvider Used in permission control for requested actions com.sap.user.BusinessPartner Used to access the current sold-to party (in particular the key) if a known user is logged on com.sap.common.Converter Used to provide converters from internal formats to external formats, such as date or unit key that are also used by shopping templates com.sap.common.Catalog Used to access the product catalog com.sap.sales.Basket Used to perform an "add-to-cart" action in the shopping cart business object com.sap.sales.Checkout Used to access the maximum quantity per shopping template item Optional Module Interfaces com.sap.wcf.Menu com.sap.productAvailability Used to access product availability configuration to check whether display of rough stock information is enabled com.sap.productAvailabilityViews Used to render rough stock information for a shopping template item com.sap.ipc.IPCDataAccess Used to access IPC configuration to check whether configuration summaries will be rendered com.sap.ipc.ConfigUI Used to render configuration summary if a shopping template item is a configurable product com.sap.ipc.IPCClient Used to create new IPC item properties for internal processing com.sap.myAccounts Used to integrate with My Account page com.sap.common.Catalog.DetailPage Used to navigate to the product details page of a shopping template item Exposed Module Interfaces Business Object Interfaces com.sap.shoppingtemplates.CheckBeforeAddToShoppingTemplatePlugIn Used to check whether a catalog item can be added to a shopping template; only within the catalog. The check takes place regardless of the user logon status. com.sap.shoppingtemplates.ShoppingTemplateItemReplacementPlugIn Used to replace a catalog item to be added to a shopping template; only within the catalog. The user must be logged on. 28 October 2013 Development and Extension Guide – Application-Specific Information UI Interfaces View Components com.sap.shoppingtemplates/ShoppingTemplatesMainPageLinkInclude Link My Shopping Templates in the page header Objects None Navigation Targets com.sap.shoppingtemplates.toMyShoppingtemplates/toMyShoppingtemplates Navigation to the shopping template overview page 1.4.16 Product Views Main Module Introduction You add the Product Views Main and Product Views module of Web Channel Builder to make it possible to apply some "filtering" criteria on some attributes to a specific user context. By adding this module, an additional setting is available in the Product Catalog module that specifies the product view to be used by the shop. The configuration of the product view itself is performed by the Product View Web Channel Builder application that is integrated into Web Channel Builder. This module does not contain any specific settings for product views; however, you must include it in the configuration of your Web Channel applications if you want to use product views. Detailed Description The Product View Main and the Product View module allow the filtering of catalog content based on the following: User Context Target Group(CRM) Account Hierarchy(CRM) Main Customer Hierarchy Node(ERP) Subordinate Customer Hierarchy Node(ERP) URL Parameter URL wec-locale Attributes Category(CRM) Material Classification(ERP) Distribution Channel Sales Organization MDM Taxonomy Product views are available in both the consumer scenario and the contact scenario. Required Module Interfaces com.sap.common.ProductView com.sap.common.Catalog com.sap.wcf.Layouts Optional Module Interfaces com.sap.wcf.UserCore com.sap.user.UserDataProvider com.sap.user.BusinessPartner Exposed Module Interfaces October 2013 29 Development and Extension Guide – Application-Specific Information Business Object Interfaces ProductViewRuntime BusinessPartnerAccess UserDataProviderAccess* UserFunctionProviderAccess UI Interfaces View Components productViewRuntimeHeader Objects None Navigation Targets None 30 October 2013 Development and Extension Guide – Application-Specific Information 1.5 Application Plug-Ins Task Plugin Type Module Ref. Impl. in Module Implement additional com.sap.sales.ItemListButtons View salestransactions shoppingte buttons in the item list mplates toolbar of the shopping cart (standard or extended UI) Add new partner com.sap.sales.PartnerFunctionPlugIn Code salestransactions instore functions Show alternative com.sap.sales.AlternativeAvailabilityPlugI Code salestransactions instore availability views n com.sap.sales.AlternativeAvailabilityView View s Replace products com.sap.sales.BasketItemReplacementPl Code salestransactions article before adding to ugIn shopping cart Prevent products from com.sap.sales.CheckBeforeAddToCartPlu Code salestransactions article being added to gin shoppping cart Read or write additional com.sap.sales.SalesDocumentMapperPlu Code salestransactions loyalty data from SAP CRM gInCRM back end Add JavaScript to the com.sap.sales.salesJS View salestransactions extension order, quotation, and/or example request for quotation views Add information for a com.sap.sales.SalesOrderItemAttributesR Relatio salestransactions instore sales order item elationPlugIn n Replace products com.sap.sales.WishListItemReplacement Code wishlist article before adding to wish PlugIn list Prevent products from com.sap.wishlist.CheckBeforeAddToCart Code wishlist article being added to wish list WishListPlugIn Replace catalog item com.sap.common.Catalog.ProductDetailsI Code catalog article used on the page temReplacementPlugIn showing product details Prevent, replace, and com.sap.common.Catalog.PriceCalculatio Code catalog article delegate the pricing of nItemReplacementPlugIn catalog items Substitute catalog UI (code) Code catalog article based on catalog item's com.sap.common.Catalog.CatalogViewO type verridePlugIn (view) View com.sap.common.Catalog.ItemBlockView (view) com.sap.common.Catalog.ItemListView (view) com.sap.common.Catalog.DetailContentU pper October 2013 31 Development and Extension Guide – Application-Specific Information (view) com.sap.common.Catalog.DetailMiddleSe ction Add additional MDM com.sap.common.Catalog.FilterExpansio Code catalog article taxonomy table as nPlugIn catalog filters Replace the catalog ID com.sap.common.Catalog.CatalogSearch Code catalog E-service of advanced search #1 IDPlugIn_1 Replace the catalog ID com.sap.common.Catalog.CatalogSearch Code catalog E-service of advanced search #2 IDPlugIn_2 Add UI content below com.sap.common.Catalog.BottomLeftNav View catalog campaign the left navigation Add UI content in block com.sap.common.Catalog.BlockViewBelo View catalog prodavailab view between product wTitle ility title and image Add UI content in block com.sap.common.Catalog.BlockView View catalog customerint view between product eraction detail link and price productreco mmend Add UI content in block com.sap.common.Catalog.BlockViewOthe View catalog wishlist view below the price rFunctions Add UI content in list com.sap.common.Catalog.ListViewBelow View catalog prodavailab view between product Title ility title and image Add UI content in list com.sap.common.Catalog.ListView3rdCol View catalog customerint view in the 3rd column umn eraction Add UI content in list com.sap.common.Catalog.ListView4thCol View catalog productreco view in the 4th column umn mmend (top) Add UI content in list com.sap.common.Catalog.ListViewOtherF View catalog wishlist view in the 4th column unctions (bottom) Add UI content on detail com.sap.common.Catalog.DetailMiddleCo View catalog productreco page, middle section, lumn1 mmend 1st column (top) Add UI content on detail com.sap.common.Catalog.DetailOtherFun View catalog wishlist page, middle section, ctions 1st column (bottom) Add UI content on detail com.sap.common.Catalog.DetailMiddleCo View catalog prodavailab page, middle section, lumn2 ility 2nd column Add UI content on detail com.sap.common.Catalog.DetailMiddleCo View catalog customerint page, middle section, lumn3 eraction 3rd column Add UI content on detail com.sap.common.Catalog.DetailMiddleBe View catalog instore page, middle section, lowAddToCart 4th column (bottom) Add UI content on detail com.sap.common.Catalog.TabPanelView View catalog catalog page, bottom tabs customerint 32 October 2013 Development and Extension Guide – Application-Specific Information eraction knowledge manageme nt productreco mmend Add UI content in detail com.sap.common.Catalog.SideBarView View catalog productreco page, right side bar mmend Add information for a com.sap.common.Catalog.Products Relatio catalog Instore product n productreco mmend Replace item for free com.sap.marketing.FreeGoods.FreeGood Code productrecommen article goods lookup ReplacementPlugIn d Add UI content in single com.sap.user.RegisterView View user loyalty page user registration contentman agement Add UI content in single com.sap.user.RegisterConfirmationView View user loyalty page user registration confirmation Enable processing of com.sap.user.UserRegistrationPlugIn Code user loyalty additional logic during and after user registration Add UI content in block com.sap.wec.trade.ListViewOtherFunction View article None view, below the price s Replaces com.sap.common.Catalog.ListViewOtherF unctions for generic articles Add UI content in list com.sap.wec.trade.ListViewOtherFunction View article None view, below the price s Replaces com.sap.common.Catalog.ListViewOtherF unctions for generic articles Add UI com.sap.common.header View com.sap.common extension content/JavaScript in examples the contentHeader view Add UI com.sap.common.contentHeader View com.sap.common extension content/JavaScript in examples the contentHeader view, offers access to the view handler for retrieving information such as breadcrumbs and application title Add UI content in the com.sap.main.footer View main footer view of the application Add UIcContent in the com.sap.main.header View main header view of the application Add UI content to the com.sap.ipc.otherFunctions View ipc shoppingte October 2013 33 Development and Extension Guide – Application-Specific Information sidebar view in the mplates configuration UI under the picture of the product and the total price, e.g Add to Templates button For more information about plug-ins, see the Development and Extension Guide: Generic Information for SAP Web Channel Experience Management on SAP Service Marketplace at http://service.sap.com/wec-inst, under Modules -> Module Dependencies -> Module Interface Plug-In. 1.5.1 Sales Transactions and Wish Lists Plug-Ins 1.5.1.1 Sales Transactions Plug-Ins Adding New Partner Functions If you want to read and write additional partner functions to the SAP CRM back end, you can implement the com.sap.sales.PartnerFunctionPlugIn plug in. You must define the following: The mapping between business partner role and partner function A list of business partner roles for the system to process (in order to read and write additional business partner roles) A list of business partner roles written for items Showing Alternative Availability Views If you want the system to show an alternative availability view for sales transactions, implement the following plug-ins: com.sap.sales.AlternativeAvailabilityPlugIn You can control whether the system shows the alternative availability view for a specific item. com.sap.sales.AlternativeAvailabilityViews You can define which of the following views the system uses as an alternative availability view: o basketRichUIAvailability Used in the shopping cart of the extended UI o basketLeanUIAvailability Used in the shopping cart of the standard UI o orderRichUIDelivery Used in the order and in checkout Replacing Products Before Adding to Shopping Cart If you want to adjust or replace products before they are added to the shopping cart, you can implement the plug-in com.sap.sales.BasketItemReplacementPlugIn. Your implementation will receive a status and a list of items that will be added to the shopping cart. The status can be used to prevent the items from being added to the shopping cart and to add messages to the UI. The item list can be changed to adapt the items to be added to the shopping cart. In summary, items can be added, replaced, or removed from the list. Preventing Products from Being Added to the Shopping Cart There is a possibility to check products before they are added to the shopping cart. By implementing the plug-in com.sap.sales.CheckBeforeAddToCartPlugin, you will be able to check the item before it is processed. Any messages created will be displayed on the Web shop UI. Reading or Writing Additional Data from the SAP CRM Back End To read or write additional data from the RFC function modules CRM_WEC_ORDER_READ and CRM_WEC_ORDER_SET, you can use plug-in com.sap.sales.SalesDocumentMapperPlugInCRM. You must define 34 October 2013 Development and Extension Guide – Application-Specific Information the data to be requested (or set). You must also read or write the data to the RFC call. The processing of the additional data must be added to the function modules. As an alternative, you can use the extension concept of the SAP CRM back end. In this case, you do not have to use this plug-in, but can enhance the class ExtensionMapper for the SAP CRM back end. 1.5.1.2 Wish List Plug-Ins Replacing Products Before Adding to the Wish List If you want to adjust or replace a product before it is added to the wish list, you can implement the plug-in com.sap.sales.WishListItemReplacementPlugIn. Your implementation receives a status and a list containing the item to be added to the wish list. The status can be used to prevent the item from being added to the wish list and to add messages to the UI. The item in the item list can be changed. The list must only contain 1 item. If the status is set to error, the list might be empty. Preventing Products from Being Added to the Wish List There is a possibility to check products before they are added to the wish list. By implementing the plug-in com.sap.wishlist.CheckBeforeAddToCartWishListPlugIn, you can check the item before it is processed. Any messages created are displayed on the Web shop UI. October 2013 35 Development and Extension Guide – Application-Specific Information 2 Generic Topics 2.1 Application Modules You can create a new Web Channel module from scratch and integrate the module into the common application infrastructure. 2.1.1 Creating and Integrating New Modules into the Application You can use a wizard to create new modules for Web Channel Builder. You can either generate only the module parts that are needed or generate all three (that is, md, ui, and bo) as shown in the following figure: 36 October 2013 Development and Extension Guide – Application-Specific Information The deployment unit of the new module has to be added to the extension application as a dependency. In this way, we make sure that the new module is deployed with the whole application, as shown in the following figure: In Web Channel Builder, the new module is shown as part of the customer namespace when adding it to the configuration, as shown in the following figure: Now we can add content to the new module, for example add a new page showing a simple text as content, as shown in the following code: <!DOCTYPE ui:composition SYSTEM "-//W3C//DTD XHTML 1.0 Transitional//EN"> <ui:composition xmlns:ui="http://java.sun.com/jsf/facelets" xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:wcf="http://java.sun.com/jsf/composite/wec" October 2013 37 Development and Extension Guide – Application-Specific Information xmlns:wecf="http://java.sap.com/wec/wcf/composition" template="#{wecf:getBasePage('invoices','invoicePage')}"> <ui:define name="baseExtension"> <ui:decorate template="#{wecf:getPageLayout('invoices','invoicePage')}"> <ui:define name="content"> <wcf:pageArea areaName="content" id="paCAU"/> </ui:define> </ui:decorate> </ui:define> </ui:composition> <?xml version="1.0" encoding="UTF-8" standalone="no"?> <UIRepository xmlns="http://www.sap.com/wec/wcf/viewcomposition/ui-repository" xmlns:wec="com.sap.wec.core.config" module="invoices"> <PageReference moduleInterface="com.sap.main" moduleInterfacePage="basePage" name="refBasePage" /> <Page defaultLayout="1column" name="invoicePage" contentArea = "contentInvoice" extends="refBasePage" ownLayoutUsed="true" menu="highlightInvoice"> <Layout name="1column"/> <Area defaultInclude="invoiceInclude" name="content"/> </Page> <Layout name="1column" moduleInterfaceLayout="1column" moduleInterface="com.sap.wcf.Layouts" /> <UIInclude name="invoiceInclude"/> </UIRepository> 2.1.2 Integrating the New Module into the Common Application Infrastructure Once you have created a new module, you can integrate it into the common application infrastructure and add the following: Breadcrumbs for the new page A new menu entry corresponding to the new functionality A new entry in the My Account area of the Web shop 2.1.2.1 Adding a New Entry in My Account After following the steps below, you will be able to configure the My Account module by using Web Channel Builder in such a way that a new entry corresponding to the module you have created is available in the left menu navigation of My Account. 1. In the metadata part of the new module, create a file called myaccount.xml with the following content: <LEFTMENU xmlns:wec="com.sap.wec.core.config" xmlns:x="http://www.w3.org/2001/XInclude"> <MENUITEM type="4" level="1" position="3"> <INAME resourcekey="invoices.ui.myaccount.invoice" id="iP">Invoice</INAME> <TARGET>toInvoice</TARGET> </MENUITEM> 38 October 2013 Development and Extension Guide – Application-Specific Information </LEFTMENU> 2. Define the navigational target toInvoice in the the ui-repository.xml, which belongs to the ui part of the module, as shown in the following code: <?xml version="1.0" encoding="UTF-8" standalone="no"?> <UIRepository xmlns="http://www.sap.com/wec/wcf/viewcomposition/ui-repository" xmlns:wec="com.sap.wec.core.config" module="invoices"> ... <NavigationTarget name="toInvoice" targetComposition="Area:invoiceInclude"/> ... </UIRepository> 3. Register the myAccount.xml file in the metadata.xml, as shown in the following code: <module xmlns="http://www.sap.com/wec/frw/tc/modules/metadata" lazyLoad="true" mainModule="false" moduleID="invoices"> <moduleType>application</moduleType> <configForModule>invoices</configForModule> ... <config-file namespace="customer" part="md" type="myaccount">myaccount.xml</config-file> ... </module> 2.1.2.2 Adding a New Entry to the Menu Shown in the Header Area of the Application After completing the steps below you will see a new menu entry corresponding to the new module (in the header area of the application). The menu in the header area of the application that contains the links to the main areas of the application, such as Shop, My Account, Service and Support, is not configurable in Web Channel Builder. The definition of the menu is part of the main module; therefore, in order to define new menu entries, you must create an extension of the main module. In the ui part of the extended main module, define the menuConfig.xml as follows: <MenuConfiguration xmlns:wec="com.sap.wec.core.config"> <wec:ifValue variable="${invoices#_ACTIVE_}" value="true"> <Menu name="invoices" navigation="toMyInvoices" order = "4000" description="main.ui.header.invoices.menu" /> </wec:ifValue> <MenuMapping moduleMenuName="invoices:highlightInvoice" menuName= "invoices"/> </MenuConfiguration> The definition of the new menu entry is surrounded by an ifValue expression with the purpose of making the menu entry visible only if the new module:invoices is active in the configuration of the shop. The MenuMapping tag specifies which menu item should be highlighted when the Web shop customers are on a page that belongs to the invoices module. <Page defaultLayout="1column" name="invoicePage" contentArea = "contentInvoice" extends="refBasePage" ownLayoutUsed="true" October 2013 39 Development and Extension Guide – Application-Specific Information menu="highlightInvoice"> <Layout name="1column"/> <Area defaultInclude="invoiceInclude" name="content"/> </Page> The navigational target toMyInvoices is defined in the ui-repository.xml of the extended Main module: <?xml version="1.0" encoding="UTF-8" standalone="no"?> <UIRepository xmlns="http://www.sap.com/wec/wcf/viewcomposition/ui-repository" xmlns:wec="com.sap.wec.core.config" module="main"> <NavigationTarget name="toMyInvoices" moduleInterface="com.sap.customer.invoices.Invoice" moduleInterfaceTarget="toMyInvoices"/> </UIRepository> The module interface com.sap.customer.invoices.Invoice is defined in the interfaceDefinition.xml in the metadata part of the Invoices module. The extended main module has a dependency to this interface and can use only what the invoices module exposes via this interface: <module-interfaces xmlns="http://www.sap.com/wec/frw/tc/modules/metadata/interfaceDefinitions" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sap.com/wec/frw/tc/modules/metadata interfaceDefinitions.xsd"> <!-- Module interface for including account views --> <module-interface name="com.sap.customer.invoices.Invoice"> <navigationTarget name="toMyInvoices" /> </module-interface> </module-interfaces> The actual navigation target with the same name toMyInvoices is defined in the ui-repository.xml that belongs to the ui part of the invoices module: <NavigationTarget name="toMyInvoices" targetComposition="Page:invoicePage"/> 2.1.2.3 Adding Breadcrumbs to a Page Belonging to a New Module You can create breadcrumbs for a page belonging to the newly created Invoices module. The breadcrumbs in the Web shop are not navigation paths, but are rather hierarchical paths. Therefore, you must define breadcrumbs in a configuration file, which is defined in the extended main module. 1. In the ui part of the extended main module, define the breadcrumbConfig.xml file as shown in the following code: <BreadcrumbConfiguration> <BreadcrumbTrail name="invoices:invoiceBC" > <BreadcrumbEntry name="myAccount" order = "10" target="toMyAccount" description="main.ui.header.myaccount" /> <BreadcrumbEnd name="end" description="main.ui.header.myaccount.invoice" hasId="false"/> </BreadcrumbTrail> </BreadcrumbConfiguration> 40 October 2013 Development and Extension Guide – Application-Specific Information 2. Register the breadcrumbConfig.xml file in the metadata.xml file of the main module, as shown in the following code: <module xmlns="http://www.sap.com/wec/frw/tc/modules/metadata" lazyLoad="true" mainModule="true" moduleID="main"> <moduleType>application</moduleType> <configForModule>main</configForModule> <config-file namespace="customer" part="ui" type="breadcrumbs">breadcrumbConfig.xml</config-file> .... </module> 3. Use the breadcrumb defined in the extended main module in the ui-repository.xml file of the invoices module, as shown in the following code: <ViewComponent name="invoiceView" breadcrumb="invoiceBC" /> October 2013 41 Development and Extension Guide – Application-Specific Information 2.2 Currency Converters Currency converters, like other converters or validators, are managed by JSF and registered in the faces-config.xml file. This implies that the extension technique is different compared to extending configuration files that are managed by the SAP Web Channel Experience Management framework (WCEM). While a new implementation of a converter or a validator resides in an extended WCEM module like for other WCEM entities, the extension of the faces-config.xml file does not need to be declared, but a JSF specific tag needs to be used to guarantee that the order of interpreting the different faces-config.xml files is correct. Extending the Common Settings Module As converters are part of the Common Settings module (com.sap.common) and need infrastructure, an extension of the common m module needs to be done with the WCEM eclipse plug-in. Only the md and ui parts are necessary. The plug-in also generates the DPU development component. The following figure shows the module settings: Note Depending on the version, the plug-in does not take care of the module type. As the common module is a system module (that is, always available), you should check the module type in the metadata.xml. If the module type is application, Web Channel Builder raises an exception. 42 October 2013 Development and Extension Guide – Application-Specific Information Therefore, metadata.xml must look like this for the extended common module: ... <moduleType>system</moduleType> ... Implementing and Registering New Converter Implement a new converter in the ui part of the extended common module. Note that for you to be able to access the SAP version of the Common Settings module, both the ui and the dpu part need the appropriate references to the standard development components. For the DPU, a reference to wec/comm/mc/common/dpu is necessary. Register the new implementation in the faces-config.xml as shown in the following code (and also specify the ordering of the faces-config files so that your version is processed after the standard ones have been inspected): <?xml version="1.0" encoding="UTF-8"?> <faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation= "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd" version="2.0"> <name>extension</name> <ordering> <after> <others /> </after> </ordering> <converter> <converter-id>wecCurrency</converter-id> <converter-class> com.customer.wec.app.common.ui.converter.CurrencyConverter</converter-class> </converter> </faces-config> October 2013 43 Development and Extension Guide – Application-Specific Information 2.3 Central Header and Footer This example demonstrates how to add information to the common application header or footer, and how to replace the standard footer with a custom one. Creating a New Module You need to create a new module, and attach it to your Java application and Web Channel Builder application. Since the extension of header and footer is possible via a plug-in, this new module does not need to be an extension of the Main module in the sap namespace. You can check the development components starting with wec/extexample that are part of software component SAP-WEC. This new module needs the md, the bo, and the ui parts. Adding Information to Application Header The application header provides the plug-in com.sap.main.header. You can declare its implementation in the metadata.xml file of your module: <interfaceImplementation interfaceName="com.sap.main.header"> <view viewName="plugIn" usedView="additionalHeader" /> </interfaceImplementation> This declaration states that you need to provide the include additionalHeader.xhtml that points to a corresponding component. The component could look as follows: ... <cc:interface componentType="sap.wec.ViewComponent"> </cc:interface> <cc:implementation> <wec:panelGroup id="pgExtToolbarBtns" styleClass="fw-toolbar-btn"> <wec:commandButton value="#{i18n['basics.ui.header.menu1']}"></wec:commandButton> <wec:commandButton value="#{i18n['basics.ui.header.menu2']}"></wec:commandButton> </wec:panelGroup> <wec:outputText id="addHdr" styleClass="fw-link-bt-text" value="#{i18n['basics.ui.header']}" /> </cc:implementation> ... Adding Information to Application Footer The application footer provides a plug-in that is similar to the one described in the section above, called com.sap.main.footer. You can declare its implementation in the metadata.xml file of your module: <interfaceImplementation interfaceName="com.sap.main.footer"> <view viewName="plugIn" usedView="footer" /> </interfaceImplementation> This declaration states that you need to provide the include footer.xhtml that points to a corresponding component. The component could look like this: ... <cc:interface componentType="sap.wec.ViewComponent"> </cc:interface> 44 October 2013 Development and Extension Guide – Application-Specific Information <cc:implementation> <wec:panelGroup layout="block" styleClass="fw-footer-box"> <wec:outputText id="oTHL" styleClass="fw-footer-title" value="#{i18n['basics.ui.footer']}" /> </wec:panelGroup> </cc:implementation> ... Disabling the Standard Footer If you want to remove the entire existing footer, the plug-in com.sap.main.footer, mentioned above, also provides a Java part that allows you to disable the standard footer. To achieve this, you need to introduce a module access class for the new module, and register it in the metadata.xml file. <moduleClasses> <moduleAccessClass>com.sap.customer.basics.modulemgmt.BasicsModuleAccess</moduleAccessClas s> </moduleClasses> This module access class would then state that the standard footer should be hidden, and annotate this method with the name of the plug-in: @ModuleInterfacePlugin(interfaceName = "com.sap.main.footer") public FooterPlugIn getFooterPlugIn() { return new FooterPlugIn() { public void controlStandardFooter(ControlFooter control) { control.hidden = true; } }; } October 2013 45 Development and Extension Guide – Application-Specific Information 2.4 JavaScript for Web Analytics This example demonstrates how to put JS code in central parts of the WCEM application, to enable basic Web analytics. There are much more sophisticated techniques available if specific actions should be tracked. This is possible for example via extensions of the 'comp.theme' module and by enriching JS code that is connected to buttons or other UI elements. Creating a New Module You need to create a new module and attach it to your Java application and Java Web Channel Builder application. You can check the development components starting with wec/extexample which are part of software component SAP-WEC; this example also covers these DCs. This new module needs the md, bo, and ui parts. Central JS for Page Tracking The system module provides a plug-in com.sap.common.header that allows you to extend the application header. In metadata.xml, its implementation can be declared like this: <interfaceImplementation interfaceName="com.sap.common.header"> <view viewName="plugIn" usedView="genericJS" /> </interfaceImplementation> Create an include ../includes/genericJS.xml which points to the actual component in ../components like this <!DOCTYPE ui:composition SYSTEM "-//W3C//DTD XHTML 1.0 Transitional//EN"> <ui:composition xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:basics="http://java.sun.com/jsf/composite/customer/basics/components"> <basics:genericJS id="cGJS" /> </ui:composition> The composite component could then look like this. Note that in the example, no CC handler is needed. If you need your own Customizing to be included in the JS, a CC handler is required that, for example, can read attributes such as a tracking key from the new module's configuration. <cc:interface componentType="sap.wec.ViewComponent"> </cc:interface> <cc:implementation> <script type="text/javascript"> //Generic JS, e.g. for page tracking. This coding will be part of any WCEM page </script> </cc:implementation> Note There is another plug-in com.sap.common.contentHeader available that allows you to use general application information within JS; this can be used to make the application title or the breadcrumbs available for Web analytics. This view plug-in has an instance of com.sap.wcf.beans.contentheaderinfo.ContentHeaderInfoVCHandlerInterf available that provides this data. 46 October 2013 Development and Extension Guide – Application-Specific Information Tracking Orders and Order Items The salestransactions module provides a plug-in com.sap.sales.salesJS that is included on the pages for order and quotation display. You can declare its implementation as follows: <interfaceImplementation interfaceName="com.sap.sales.salesJS"> <view viewName="plugIn" usedView="salesJS" /> </interfaceImplementation> As in the section above, an include called salesJS that points to the corresponding composite component needs to be provided. The implementation of the composite component could be similar to the following one, extracting header and item information and making it available for JS. This coding assumes that a CC handler is present that provides the items from the view interface data. As a reference, see com.sap.customer.basics.ui.SalesJSHandlerImpl in DC wec/extexample/basics/ui. .. <cc:interface componentType="sap.wec.ViewComponent"> <cc:attribute name="salesDocumentBeanJS" type="com.sap.wec.app.esales.module.transaction.ui.beans.interf.SalesDocumentJSInbound" /> </cc:interface> <cc:implementation> <script type="text/javascript"> var confirmation= #{cc.attrs.salesDocumentBeanJS.orderConfirmation}; if (confirmation){ //This will only be executed in the context of order confirmation. //You might put javascript here related to orders and items. E.g. for web analytics purposes. //Example: Order ID: #{cc.attrs.salesDocumentBeanJS.salesDocumentBean.id} //Order gross value: #{cc.vch.header.grossValue} } </script> <ui:repeat id="jscrItemExt" value="#{cc.vch.items}" var="item"> <script type="text/javascript"> var confirmation= #{cc.attrs.salesDocumentBeanJS.orderConfirmation}; if (confirmation){ //This will only be executed in the context of order confirmation. //Example: Extract item information like this //Product ID : #{item.productId} //Item gross value : #{item.grossValue} } </script> </ui:repeat> </cc:implementation> .. October 2013 47 Development and Extension Guide – Application-Specific Information 2.5 Country-Specific Address Formats You can add a country-specific view for rendering addresses. In the standard system, the following address formats are provided: Japanese United States European In this example, we add a address format (that is, family name followed by given name). The family name is displayed at the top of the address details view. 2.5.1 Setting Up the SAP CRM or SAP ERP Back End SAP CRM Back End 1. Define the new address layout in Customizing for SAP CRM under Customer Relationship Management -> SAP Web Channel Experience Management -> Basic Settings -> Define Address Layouts. 2. Define a new address layout as key 03. 3. Assign the new address layout to the address layout keys as needed. 4. Map the address layout keys to countries in Customizing for SAP CRM under SAP NetWeaver -> General Settings -> Set Countries -> Specify Countries in mySAP Systems (CRM, SRM, SCM, …). SAP ERP Back End 1. Define the new address layout in Customizing for SAP ERP under Sales and Distribution -> SAP Web Channel Experience Management -> Basic Settings -> Define Address Layouts. 2. Define a new address layout as key 3. 3. Assign the new address layout to the address layout keys as needed. 4. Map the address layout keys to countries in Customizing for SAP ERP under SAP NetWeaver -> General Settings -> Set Countries -> Specify Countries in mySAP Systems (CRM, SRM, SCM, …). 2.5.2 Creating New Views for New Address Display The system searches for address views with the Web Channel address layout key as suffix (in this example, key 03). You only need to do extensions in the md and ui part of the user module. You need to create composite components (that is, views) with the following names (and also the corresponding include files): META-INF/resources/customer/user/components/user/bp/address/addressLayout03.xhtml META-INF/resources/customer/user/components/user/bp/address/addressLayoutReadonly03.xhtml Declaring the ui-repository.xml File in the Customer Namespace In the md part of the extended user module, you must declare the customer version of the ui repository in the metadata.xml file, as shown in the following code: <config-file namespace="customer" part="ui" type="ui-repository">ui-repository.xml </config-file> Creating and Registering New Views in the Customer Namespace You need to create the new views in the ui part. To create the views, copy the standard views and includes, which you can find at the following locations: META-INF/resources/sap/user/includes/user/bp/address META-INF/resources/sap/user/components/user/bp/address Ensure that you make the required changes to the address format. The target directories in your version of the user module should look like this, assuming the extension namespace is called customer: META-INF/resources/customer/user/includes/user/bp/address META-INF/resources/customer/user/components/user/bp/address Note that in the include file, you also need to refer to the correct namespace, as shown in the following code: 48 October 2013 Development and Extension Guide – Application-Specific Information <ui:composition xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:userBpAddress= "http://java.sun.com/jsf/composite/customer/user/components/user/bp/address"> <userBpAddress:addressLayout03View id="addlayinc" viewInterface="#{viewInterface}"/> </ui:composition> Register the new views in the ui-repository.xml file as shown in the following code: <ViewComponent componentHandlerClassName= "com.sap.wec.app.common.module.user.ui.bp.address. handler.impl.AddressLayoutViewHandlerImpl" name="addressLayout03View" /> <ViewComponent componentHandlerClassName= "com.sap.wec.app.common.module.user.ui.bp.address. handler.impl.SingleAddressReadOnlyViewHandlerImpl" name="addressLayoutReadonly03View" /> October 2013 49 Development and Extension Guide – Application-Specific Information 2.6 Store Locator - Google Maps 2.6.1 Store Locator A typical extension of the store locator is to make the delivered example integration of Google Maps the productive version. If another map should be integrated or further enhancements to the example should be done, the integration interface is also described below. 2.6.1.1 Setting the Example Implementation to Productive An example that embeds the Google Map in the graphical store locator by using the integration interface described here can be found in the Javascript file graphical-map-script-google-example.js. See the information below on how to enable the example integration in Web Channel Builder. Caution SAP does not provide licensing for the Google Map or Geocoding API. You must ensure that you take steps to fulfill all licensing conditions. Therefore, before you use Google services, you must contact Google to obtain the necessary right of use. For more information about terms of service, see http://code.google.com/apis/maps/terms.html#section_10_12.. When the example integration is enabled, the graphical store locator can be used for testing purposes. However, the system displays a text at the top of the map that indicates that the implementation is only an example, as shown in the following figure: To remove this text and to have the example integration as the productive version, you must extend the Web shop as follows: 1. Create an extension for the storelocator module. 2. In the new ui DC, create a new class which extends class GraphicalMapViewHandlerImpl and overwrite only the method isRenderExampleString. The new method should only contain a return false; statement. 3. In the new ui DC, create a ui repository which contains the following (note that ExtensionFromGraphicalMapViewHandlerImpl must be replaced by the name of your class): ?xml version="1.0" encoding="UTF-8" standalone="no"?> <UIRepository xmlns="http://www.sap.com/wec/wcf/viewcomposition/ui-repository" xmlns:wec="com.sap.wec.core.config" module="storelocator"> <ViewComponent componentHandlerClassName="ExtensionFromGraphicalMapViewHandlerImpl" name="graphical-map"/> </UIRepository> 50 October 2013 Development and Extension Guide – Application-Specific Information 2.6.1.2 Settings in Web Channel Builder The following settings are relevant for the integration of a graphical map: Path to JavaScript File for Map Integration The path to the Javascript file that contains the implementation of the map integration must be entered. The path to the example implementation is sap/storelocator/ui/scripts/graphical-map-script-google-example.js. Determine Geocoordinates in SAP CRM Back End If this setting is activated, the geocoordinates of the stores are determined in the SAP CRM back end and transferred to the graphical map where the locations of the stores are marked accordingly. The setting is available only if the setting Show Distances to Stores in Search Results is not activated. If this setting is activated, then the geocoordinates are determined in the SAP CRM system and transferred to the graphical map by default. If the geocoordinates are not determined in the SAP CRM system, then the addresses of the stores can be used to determine the geocoordinates by calling a geocoder using Javascript. The example implementation described uses the geocoder service from Google in this case. Key for Map Integration In this setting, you can enter a key (or client ID) for the map integration. The usage of the example implementation of the Google Map described requires a client ID from Google, which can be entered in this field. 2.6.2 Graphical Map Interface 2.6.2.1 Interface for Map Integration You can integrate a graphical map from a third-party vendor to display the locations of stores graphically. The integration of a map can be done by using the Javascript interface, which is located in the view component graphical- map.xhtml. The integrated map is displayed at a predefined place on the UI of the graphical store locator. The following figure shows a schematic overview of the interaction between the Internet browser and the Java-server when Web shop customers enter search criteria and search for stores: During the construction of the html page in the Java-Server (see 1 in the figure above), the data needed for the map integration is constructed. This data is then passed to the map integration by way of a set of global Javascript variables, which are located in the view component graphical-map.xhtml. These global Javascript variables are the interface to the map integration. In the construction step of the html page, the assignment statements that fill the global variables are constructed. The execution of these assignment statements is not carried out here but in the next step after the loading of the page in the Internet browser. After the execution of the assignment statements, the system calls special Javascript hook methods that must be implemented in order to display the map. In the next step (see 2 in the figure above), the Internet browser loads the generated html page first and then carries out the Javascript coding for the map integration. The integration must contain the implementation of the two hook methods and can be October 2013 51 Development and Extension Guide – Application-Specific Information done in an own Javascript file (that is, .js). The path to this Javascript file can be entered in a configuration setting of the store locator module in Web Channel Builder. An example implementation that embeds the Google Map into the store locator using this Javascript interface is part of the delivery. The technical details that are used in order to fill the data in the interface are explained below. This description can be helpful if an enhancement of the interface is necessary. 2.6.2.2 Global Javascript Variables in the graphical-map.xhtml File The Javascript coding that is embedded in the view component graphical-map.xhtml contains several global variables that are used to transfer data to the map integration. These global variables are the interface to the map integration. The following explains the content of these global variables: Variable Content gv_gsl_country_name The name of the country that the user has selected in the selection screen in the language used in the browser. gv_gsl_region_name The name of the state/region that the user has selected in the selection screen in the language used in the browser. gv_gsl_address_string Concatenation of the addresses of all stores that were found in the last search. gv_gsl_index_to_csv Contains the “Index to” for each address in gv_gsl_address_string. The values are separated by the character in gc_gsl_value_separator (which is a comma by default; CSV = Comma-Separated Values) gv_gsl_event The last “event” that the user has initiated. Possible values: gc_do_search_event User has clicked the Search button gc_gsl_change_state_event User has selected another state in the state dropdown listbox gc_gsl_change_country_event User has selected another country in the state dropdown listbox gc_gsl_select_store_event User has selected one store in the list containing the search results gc_gsl_reset_search_event User has clicked the Clear link in the selection view gc_gsl_switch_to_graphical_event User has switched from textual to graphical store locator gv_gsl_map_values_csv String that has been passed to the Java server via hidden input field in the last step gv_gsl_lat_csv Latitudes of all stores that were found in the last search. This variable is only filled if one of the settings Use Geocoding from the back end and Show Distances to Stores in Search Results is activated in the configuration. If the geocoding data of a store cannot be found in the back end, the latitude is 0 for this store. gv_gsl_lng_csv Longitudes of all stores that were found in the last search. This variable is only filled if one of the settings Use Geocoding from the back end and Show Distances to Stores in Search Results is activated in the configuration. If the geocoding data of a store cannot be found in the back end, the longitude is 0 for this store. gv_gsl_sel_store_html_id The ID of the UI component that contains the html coding of the details of the store that the user has selected in the result list (to be shown in an info window in the map). gv_gsl_store_list_data_table_id The ID of the data table that contains the html coding with the details of all stores found in the last search (to be shown in an info window in the map). 52 October 2013 Development and Extension Guide – Application-Specific Information gv_gsl_selected_store_address The address of the store that the user has selected in the result list. gv_gsl_input_field_map_values_id The ID of the hidden input field that can be filled via Javascript in order to pass values to the Java Server. gv_gsl_selected_store_lat The latitude of the store that the user has selected in the result list. This variable is only filled if one of the settings Use Geocoding from the back end and Show Distances to Stores in Search Results is activated in the configuration. gv_gsl_selected_store_lng The longitude of the store that the user has selected in the result list. This variable is only filled if one of the settings Use Geocoding from the back end and Show Distances to Stores in Search Results is activated in the configuration. gv_gsl_selected_store_geo_found Boolean value that indicates whether the geocoordinates of the store that the user has selected in the result list have been found in the back end. true – geocoordinates found false – geocoordinates not found gv_gsl_city The city that the user has entered in the selection field City. gv_gsl_store_id_csv Concatenation of the IDs of all stores found in the last search (separated by the character gc_gsl_value_separator). gv_gsl_key_for_map_integration Key for map integration as defined in the configuration settings of the store locator in Web Channel Builder. gv_gsl_is_secure Information whether the application is running in secure mode (using https) or in unsecure mode (using http). true – secure mode false – unsecure mode gv_gsl_message_no_coords_found Predefined message text that can be shown if the coordinates of the store that the user has clicked in the result list could not be determined by the geocoding service. gv_gsl_search_panel_id The client ID of the panelGroup that contains graphical search view and graphical result view. gv_gsl_is_show_distance_in_result_list Boolean value that indicates whether distance search is used. true – distance search is used false – normal search is used gv_gsl_last_store_index_in_paginator Index of the store that is displayed at the last position on the current page. Is needed for the zooming functionality in the distance search. gv_gsl_lat_start_address Latitude of the start address for the distance search. gv_gsl_lng_start_address Longitude of the start address for the distance search. gv_gsl_you_are_here_title Predefined text in the language used by the user (English: You are here) that is displayed in the map in order to identify the starting point of the distance search. gc_gsl_do_search_event Constant StoreSearch.DO_SEARCH_EVENT ( = "SEARCH_EVENT") gc_gsl_change_region_event Constant StoreSearch.CHANGE_REGION_EVENT ( = "CHANGE_REGION_EVENT") gc_gsl_change_country_event Constant StoreSearch.CHANGE_COUNTRY_EVENT ( = "CHANGE_COUNTRY_EVENT") gc_gsl_select_store_event Constant StoreSearch.SELECT_STORE_EVENT ( = "SELECT_STORE_EVENT") gc_gsl_value_separator Constant StoreSearchBeanImpl.VALUE_SEPARATOR October 2013 53 Development and Extension Guide – Application-Specific Information (= ",") gc_gsl_apply_map_values_event Constant StoreSearch.APPLY_MAP_VALUES_EVENT ( = "APPLY_MAP_VALUES_EVENT") gc_gsl_reset_search_event Constant StoreSearch.RESET_SEARCH_EVENT ( = "RESET_EVENT") gc_gsl_switch_to_graphical_event Constant StoreSearch.SWITCH_TO_GRAPHICAL_EVENT ( = "SWITCH_TO_MAP_EVENT") 2.6.2.3 Javascript Hook Methods in the graphical-map.xhtml File The Javascript coding that is embedded in the view component graphical-map.xhtml is divided into two parts: The first part is carried out at the point in time whern the whole page is loaded in the Web browser. This part contains the assign statements that fill the global JavaScript variables, as well as a call of the hook method com.sap.wec.appl.storelocator.gsl_load_script(). This call is carried out after the page has been loaded in the Web browser and can be used to instantiate and display the graphical map (example: the point in time when the graphical store locator is displayed the first time). The second part is carried out at the point in time when the user triggers an AJAX event that needs to refresh the already displayed graphical map. This part also contains the assign statements that fill the global JavaScript variables and a call of the hook method com.sap.wec.appl.storelocator.gsl_load_script_on_ajax().This call is carried out after the parts of the html page related to the AJAX event have been loaded in the Web browser. The method can be used to refresh the graphical map that is already displayed at that time (example: the user clicks the Search button and the stores found are marked on the graphical map). 2.6.2.4 Call of a Getter Method This is the easiest way to transfer data from the Java server to the JavaScript implementation. Inside the JavaScript coding of the map integration, a getter method of one of the Java beans can be called in order to fill a JavaScript variable with the data. The Java beans that are related to the view component graphical-map.xhtml are the view component handler (GraphicalMapViewHandlerImpl.java) and the BO bean (StoreSearchBeanImpl.java). If, for example, the enhancement of the interface with the additional field myProperty of the BO bean StoreSearchBeanImpl is necessary then this can be done in the following way: The property myProperty and the getter method getMyProperty are added to the BO bean In the JavaScript coding, a variable can be filled with the value of the property in the following way: gv_gsl_my_property = '$ {this.storeSearchBean.myProperty}'; During the construction time of the html page in the Java server the call of the getter method is carried out. That is why in the html coding that is sent to the browser only the result of this call is visible, for example, gv_gsl_my_property = ‘XYZ’ 2.6.2.5 Display of Generated HTML Coding It is possible to access parts of the generated html page inside the map integration. This mechanism can be used in order to display detailed data of one store inside the map (with a so called “Info Window”). The following steps have to be carried out in order to implement this: Creation of a “binding” for the desired UI component. With a binding (attribute binding of the UI component) the desired UI component is linked to a property of the related Java bean. The implementation of the Java bean must contain a property of the correct type and a setter method that sets this property. Providing a getter method for the AD of the UI component. In the related Java bean, a getter method must be implemented that provides the ID of the linked UI component. Access to generated html coding In the JavaScript coding of the map integration, the getter method for the ID of the UI component can be called and then the html coding can be accessed, for example, using the JavaScript command innerhtml. The following is an example in GraphicalMapViewHandlerImpl.java: 54 October 2013 Development and Extension Guide – Application-Specific Information Property: selStoreUIComponent Setter method: setSelStoreUIComponent Getter method for the UI component: getSelStoreHtmlId 2.6.2.6 Transfer of Data from Javascript to the Java-Server by Hidden Field The transfer of data from the JavaScript coding of the map integration to the Java server can be done by filling a hidden input field with the desired data and by transferring this input field with the next request. The hidden input field, which can be used for this purpose, is located in the view component graphical-search.xhtml (id = iTMapValues). If the hidden input field is filled, then its content is available after the next request in the global JavaScript variable gv_gsl_map_values_csv. October 2013 55 Development and Extension Guide – Application-Specific Information 2.7 Store Locator - NAVTEQ Maps Note Ensure that you follow the guidelines about how you can extend the store locator. For more information, see Store Locator - Google Maps. You can extend the Web shop by implementing NAVTEQ instead of Google. The implementation of NAVTEQ maps is based on the general extension concept. The whole implementation is done in the customer namespace. Therefore, no modification is necessary from the customer perspective. The relevant information concerning NAVTEQ maps can be found in the NAVTEQ developer guide (see http://Jsapi.lbsp.navteq.com/v1/developerguide). Caution Ensure that you read and follow all NAVTEQ terms and conditions before extending the Web shop with NAVTEQ maps. You must put the component view graphical-map to the customer namespace (and the corresponding JavaScript file from resource folder resources.sap.storelocator.ui.scripts). You can implement these according to your requirements. Do not forget to redefine the view handler MapViewHandlerImpl as described in the information about the store locator. Afterwards, you can configure your Web shop and activate your specific enhancement for the storelocator module. The following figure shows the storelocator module in Web Channel Builder: 56 October 2013 Development and Extension Guide – Application-Specific Information The following screenshot shows what the graphical map might look like using NAVTEQ: October 2013 57 Development and Extension Guide – Application-Specific Information 2.8 CSS-Only Changes to Configuration UI (Status Icons) This example shows how simple UI modifications can be achieved by simply changing the CSS. Goal: The status icons on group and instance level shall be moved from the right-hand side to the left-hand side. There shall also not be any status icons on characteristic level. Before: After: Prerequisite - Creating a Theme Before adapting the CSS file, a custom theme has to be created. For information on how to create a custom theme, see the Development and Extension Guide: Generic Information. 58 October 2013 Development and Extension Guide – Application-Specific Information Identifiying Changes One possibility to try out changes made to the CSS in advance is by using the Firefox plugin "Firebug" or a similar tool. Using this, it is possible to identify the styling you want to adapt. It is even possible to make the adaption on-the- fly and check whether the result meets the expectations. With this approach, you can change the CSS so that the page matches your requirements. Change CSS As a last step you can enter the changes that you made to the CSS, in the stylesheet. If you always maintain your changes at the bottom (or in a separate file included at the end), these changes will overrule the existing rules. You only have to maintain the delta in the standard stylesheet. October 2013 59 Development and Extension Guide – Application-Specific Information /*### customer extension/adjustment ###*/ .fw-step-title span { margin: 20px; } .fw-step-title .fw-step-title-price span { margin: 0px; } .fw-dui-v1-status { display: none; } .fw-nested-accordion-step-status-image-ok, .fw-nested-accordion-step-status-image-okay, .fw- nested-accordion-step-status-image-error { left: 0px; } .fw-nested-accordion-step-status-img-ok, .fw-nested-accordion-step-status-img-okay, .fw-nested- accordion-step-status-img-error { left: 0px; } 60 October 2013 Development and Extension Guide – Application-Specific Information 3 Product Catalog 3.1 Transfer of Additional Fields from MDM to Product Catalog This section explains how to extend the product catalog to retrieve additional fields from MDM. The extension prototype was done for a CRM scenario, however the same steps apply to an ERP scenario. The only difference is that the CatalogMDMERP class must be extended instead of the CatalogMDMCRM class. In the prototype, we retrieve all 4 fields of the GTIN tuple as an example. 1. Extend the result definition to contain the additional fields. This is achieved by overriding the method below and adding to the result definition the name of the field in the main table pointing to the tuple that contains the desired fields. @Override protected ResultDefinitionManager createResultDefinitionForItems() { ResultDefinitionManager resultDefinitionForItems = super.createResultDefinitionForItems(); /** The GTIN tuple field from main item table */ resultDefinitionForItems.addField(this.rse.getField(Tables.CATALOG_ITEM_TABLE_NAME, WECMDM_CRM_GTIN)); return resultDefinitionForItems; } 2. Extend the supporting result definition to contain the desired tuple fields and any additional lookup fields required. The code snippet below covers how to fetch two different field types from the tuple: A regular field (for example, of type text) and a lookup field to another table. In the example below the fields WECMDM_CRM_UNIT_OF_MEASURE and WECMDM_CRM_GTIN_TYPE are lookups to other existing tables. @Override protected ResultDefinitionManager createSupportingResultDefinitionForItems() throws BackendException { ResultDefinitionManager srdm = super.createSupportingResultDefinitionForItems(); /** Tuple : Global Trade Item Numbers */ /** Global Trade Item Number - Text */ srdm.addField(this.rse.getTupleMemberField(WECMDM_CRM_GTINS, WECMDM_CRM_GTIN)); /** Units of Measure - Lookup [Flat] */ srdm.addField(this.rse.getTupleMemberField(WECMDM_CRM_GTINS, WECMDM_CRM_UNIT_OF_MEASURE)); /** Global Trade Item Number Type - Lookup [Flat] */ srdm.addField(this.rse.getTupleMemberField(WECMDM_CRM_GTINS, WECMDM_CRM_GTIN_TYPE)); /** Main Global Trade Item Number Indicator - Boolean */ srdm.addField(this.rse.getTupleMemberField(WECMDM_CRM_GTINS, WECMDM_CRM_MAIN_GTIN)); /** Needed for (Units of Measure - Lookup [Flat]) */ October 2013 61 Development and Extension Guide – Application-Specific Information /** Table : Units */ /** Unit of Measurement - Text */ /** * Even if this field is already added by the super call, adding this * field again cause no issues. */ srdm.addField(rse.getField(Tables.UNITS_TABLE_NAME, Fields.PRODCATALOG_UNITS_UOM_FLD_NAME)); /** Needed for (Global Trade Item Number Type - Lookup [Flat]) */ /** Table : Global Trade Item Number Types */ /** Global Trade Item Number Type - Text */ srdm.addField(rse.getField(WECMDM_CRM_GTIN_TYPES, WECMDM_CRM_GTIN_TYPE)); return srdm; } 3. Extend the CatalogItem object to contain the additional field values. MDM returns the desired values in a Record object, which is passed to the method below. The values are copied from the Record object into a container object (in this example, GTIN). This is done by first retrieving the MDM field ID of each field from the repository schema, and then fetching the corresponding values from the Record object. Finally, the container object is added to the extension map. Note that the GTIN field is multi-valued, which means that several tuple records can be returned, and a loop is needed to get all the values. @Override protected CatalogItem parseCatalogItem(Record record) throws BackendException { CatalogItem catalogItem = super.parseCatalogItem(record); /** The record's field */ FieldId gtinsFID = this.rse.getField(Tables.CATALOG_ITEM_TABLE_NAME, WECMDM_CRM_GTIN) .getId(); /** All fields in the tuple */ FieldId gtinFID = this.rse.getTupleMemberField(WECMDM_CRM_GTINS, WECMDM_CRM_GTIN).getId(); FieldId uomFID = this.rse.getTupleMemberField(WECMDM_CRM_GTINS, WECMDM_CRM_UNIT_OF_MEASURE) .getId(); FieldId typeFID = this.rse.getTupleMemberField(WECMDM_CRM_GTINS, WECMDM_CRM_GTIN_TYPE) .getId(); FieldId mainFID = this.rse.getTupleMemberField(WECMDM_CRM_GTINS, WECMDM_CRM_MAIN_GTIN) .getId(); /** Needed lookup tables */ FieldId lookupUomFID = rse.getField(Tables.UNITS_TABLE_NAME, Fields.PRODCATALOG_UNITS_UOM_FLD_NAME).getId(); FieldId lookupTypeFID = rse.getField(WECMDM_CRM_GTIN_TYPES, WECMDM_CRM_GTIN_TYPE).getId(); List<GTIN> gtins = new ArrayList<GTIN>(); MdmValue mv = record.getFieldValue(gtinsFID); if (!mv.isNull()) { /** The gtin field in the main table is a multi value tuple */ MultiTupleValue mtv = (MultiTupleValue) mv; for (MdmValue v : mtv.getValues()) { TupleValue tv = (TupleValue) v; 62 October 2013 Development and Extension Guide – Application-Specific Information GTIN gtin = new GTIN(); /** toString() is fine for TextAttributeValue & MultiregionValue */ gtin.gtin = tv.getFieldValue(gtinFID).toString(); /** The text value isn't in the tuple but the lookup table field */ gtin.uom = this.catalogHelper.getSingleValueStringLookupValue(tv, uomFID, lookupUomFID); /** The text value isn't in the tuple but the lookup table field */ gtin.type = this.catalogHelper.getSingleValueStringLookupValue(tv, typeFID, lookupTypeFID); /** MdmValue must be checked for null before being type casted */ MdmValue fieldValue = tv.getFieldValue(mainFID); if (!fieldValue.isNull()) { BooleanValue bv = (BooleanValue) fieldValue; gtin.main = bv.getBoolean(); } else { gtin.main = false; } gtins.add(gtin); } } /** This extension container is propagated to the BO.getExtensionData() */ catalogItem.getExtensionMapInternal().put(EXT_GTINS, gtins); return catalogItem; } October 2013 63 Development and Extension Guide – Application-Specific Information 3.2 Transfer of Additional Fields from CRM to MDM 3.2.1 Introduction Using a Web shop also means having different systems in use. If your system landscape includes ERP, CRM, and MDM, you often face the issue that you need more information on the Web shop side that is given in CRM, but not available on the MDM side. This section describes how you can enhance your MDM repository to have the corresponding information in MDM as well. Based on that, you can refer to the preceding section to bring this information from MDM to the Java layer. This enhancement is based on the precondition of having an existing set type in CRM (including an attribute) that you want to pass to MDM. The documentation describes the steps that need to be performed both on the CRM side (ABAP) and on the MDM side, to get the new field (attribute) from CRM to MDM. In this document, we describe how to bring the information about the country of origin to the MDM product catalog. This field exists for all products of subtype material -> trading goods. Minimum system requirements: 1. SAP Web Channel Experience Management 2.0 or higher 2. SAP CRM EhP1 or higher Out of scope: Creation of the set type that carries the additional information. Here, only the set type created beforehand is presented. Maintenance of the set type on CRM side Field extension on ERP side and transfer from CRM to MDM MDM connected directly to an ERP system Extraction of new lookup tables/customizing to MDM Products other than materials The documentation is splitted into two parts: Steps on CRM side Steps on MDM side 64 October 2013 Development and Extension Guide – Application-Specific Information 3.2.2 Steps on CRM Side 3.2.2.1 Locating the Set Type The country of origin is stored in a separate set type, ZORG_COUNTRY, which is relevant for materials only. October 2013 65 Development and Extension Guide – Application-Specific Information This set type contains only one field, the attribute ZORIGIN_COUNTRY_ATTR. The attribute ZORIGIN_COUNTRY_ATTR is defined as a CHAR3 field, like the country code it refers to. 66 October 2013 Development and Extension Guide – Application-Specific Information The assignment of set types to products takes place via transaction COMM_ATTRSET. The assignment takes place only for materials of subtype HAWA (trading goods). October 2013 67 Development and Extension Guide – Application-Specific Information Using this, it is possible to maintain the country of origin, for example, in transaction COMMPR01. In this example, we have an original babushka from Russia. 68 October 2013 Development and Extension Guide – Application-Specific Information 3.2.2.2 Bringing the Set Type to BDoc PRODUCT_MAT For this step, nothing needs to be done. As soon as the set type is put into a workbench request, the BDoc definition is updated automatically. This can be seen in transaction SBDM: The DDIC type COMT_PROD_MATERIAL_BDOC_TAB is a table with the line type COMT_PROD_MATERIAL_BDOC. The data section of the BDoc refers to DDIC structure COMT_PROD_MAT_MAINTAIN_API. This has been automatically enhanced by the new set type. October 2013 69 Development and Extension Guide – Application-Specific Information 3.2.2.3 Enhancing the MDM Outbound Adapter for PRODUCT_MAT In the MDM outbound adapter not every data segment of the PRODUCT_MAT BDoc will be forwarded to MDM. Instead, a mapping to the communication structure CRMS_MDM_MATERIAL_DATAEXCHANGE takes place. The members of this structure will then be converted into an XML file which is sent to MDM. The mapping from the BDoc structure to the communication structure takes place in class CL_CRM_MW_MDM_DATAEX_PRODMAT, method MAP_PRODMAT_DATA_TO_MDMFORMAT. At the end of this method, a BAdI call is offered to adjust or enhance the mapping. 70 October 2013 Development and Extension Guide – Application-Specific Information For the additional field, an implementation of the enhancement ES_CRM_WEC_MDM_ENHANCEMENTS and the BAdI CRM_WEC_MDM_MAPPING_BADI has to be created. The method IF_BADI_CRM_WEC_MDM_MAPPING~MAP_CRM_MDM_PRODUCTDATA has to be implemented as shown below. Depending on your specific case, the field names of <cs_dataexchange> and <is_product_mat> may be different. if_badi_crm_wec_mdm_mapping~map_crm_mdm_productdata METHOD if_badi_crm_wec_mdm_mapping~map_crm_mdm_productdata. FIELD-SYMBOLS <is_product_mat> TYPE comt_prod_material_bdoc. FIELD-SYMBOLS <cs_dataexchange> TYPE crms_mdm_material_dataexchange. FIELD-SYMBOLS <is_org_country> TYPE zorg_country_maintain. ASSIGN is_mbdoc_msg TO <is_product_mat>. ASSIGN cs_mdm_data_msg TO <cs_dataexchange>. READ TABLE <is_product_mat>-data-zorg_country INDEX 1 ASSIGNING <is_org_country>. IF sy-subrc <> 0. RETURN. ENDIF. <cs_dataexchange>-zzorigin_country = <is_org_country>-data-zz0010. ENDMETHOD. Once the BAdI implementation is active, the country of origin automatically appears in the XML file sent to MDM. <?xml version="1.0" encoding="UTF-8"?> <TABLE xmlns:asx="http://www.sap.com/abapxml"> <CRMS_MDM_MATERIAL_DATAEXCHANGE> ... October 2013 71 Development and Extension Guide – Application-Specific Information <ZZORIGIN_COUNTRY>RU</ZZORIGIN_COUNTRY> </CRMS_MDM_MATERIAL_DATAEXCHANGE> </TABLE> Note If you examine the XML file more closely you will see that the new set type may also be included in the element <SETTYPE_ATTRIBUTES>, even without implementing the mapping BAdI. Nevertheless, we recommend following the procedure described above, for the following reasons: With this approach it is also possible to enhance the set type with additional information. The element SETTYPE_ATTRIBUTES is intended for the import of MDM taxonomies. Trying to access the information of the additional set type within SETTYPE_ATTRIBUTES would result in a much more complicated mapping on MDM side, and may interfere with the existing taxonomy import mapping. 3.2.3 Steps on MDM Side This part describes the steps that need to be done on MDM side to be able to import a new field called Country of Origin to the repository. Before this step can be executed you need to ensure that the corresponding enhanced XML file is available on the file server. It must include the new field and its value. 3.2.3.1 Creating a New Field on MDM Side via MDM Console Within the MDM Console you need to create your new field for your repository. Access the MDM Console, build up a connection to your repository and unload it. After doing this, you are able to create your new field: 72 October 2013 Development and Extension Guide – Application-Specific Information 3.2.3.2 Adjusting the XML Schema You also need to update your existing XML schema. To do this, export your existing schema, store it locally, and adjust it according to your added field: October 2013 73 Development and Extension Guide – Application-Specific Information 3.2.3.3 Importing the Updated XML Schema via MDM Console After you have adjusted your schema you need to import it to the repository as well. Use the MDM Console and navigate to folder XML Schemas there. Attention: You also need to be connected to the corresponding repository, and you need to stop it before you can change the XML schema. It is possible to update the existing schema that is affected by your change. You do not need to create a new one: 3.2.3.4 Adjusting the Data Mapping After performing the steps mentioned above you need to enhance your mapping via the MDM Import Manager. There, map your new CRM field to the new MDM field. Load the relevant map first: 74 October 2013 Development and Extension Guide – Application-Specific Information Then, enhance your mapping accordingly: 3.2.3.5 Checking via MDM Data Manager Finally, you can check whether everything works correctly by using the MDM Data Manager. Start the CRM download to MDM on the CRM side. Start MDM Data Manager, where you should find the new field and its value: October 2013 75 Development and Extension Guide – Application-Specific Information 3.3 Product View Modules This guide explains how to extend product views to support modification or addition of user contexts (for CRM/ERP) or attributes (MDM). 3.3.1 Creating an Additional MDM Attribute for Product View The creation of a new attribute in the product view requires the following: 1. Extending the product view modules wec/comm/mc/productview/bo wec/comm/mc/productviewmain/bo wec/comm/mc/productviewmain/md wec/comm/mc/productviewmain/dpu wec/comm/mc/wcbproductview/bo wec/comm/mc/wcbproductview/md wec/comm/mc/wcbproductview/dpu 2. Creating a new class that implements AttributeType 3. Enhancing backendobject-config.xml files 4. Enhancing productview/wcbext/bo/helpvalues-config.xml 5. Enhancing wcf_resources.xlf 6. Enhancing sap/productviewmain/md/metadata.xml and sap.productview/wcbext/metadata.xml The current example describes the creation of a new MDM attribute based on the distribution channel tuple. During this process, the GenericTupleWithLookupAttributeImpl.java will be created. This implementation could be re-used for the Product Catalog Item tuples attribute linked to a lookup[flat]. 3.3.1.1 Extending the Product View Modules The following DC structure needs to be created: Here is the list of dependencies that need to be set up for the DCs. 76 October 2013 Development and Extension Guide – Application-Specific Information 3.3.1.2 Creating a New Implementation of Type AttributeType A new class needs to be created to provide a new MDM attribute. This class is responsible for retrieving (F4 Help) and validating the data in the configuration time, as well as for applying the constraint during the runtime. In the following example, a new GenericTupleWithLookupAttributeImpl.java class is created in the test/extens/productview/bo. To provide a generic way to deal with tuples using a Lookup[Flat] within product catalog items, GenericTupleWithLookupAttributeImpl is initialized using the metadata provided by the backendobject-config.xml. This metadata contains the proper MDM path for the attribute. public class GenericTupleWithLookupAttributeImpl extends BackendBusinessObjectBase implements AttributeType { [...] public static final String SEARCH_HELP_ID = "searchHelpId"; public static final String ATTR_DESCRIPTION = "attributeDescription"; public static final String ATTR_ID = "attributeId"; public static final String ATTR_TABLE_NAME = "attributeTableName"; public static final String ATTR_FIELD_NAME = "attributeFieldName"; public static final String ATTR_DESC_FIELD_NAME = "attributeDescriptionFieldName"; public static final String PRODUCT_TABLE_NAME = "productTableName"; public static final String PRODUCT_TABLE_FIELD_NAME = "productTableFieldName"; public static final String PRODUCT_TUPLE_NAME = "productTupleName"; public static final String PRODUCT_TUPLE_FIELD_NAME = "productTupleFieldName"; private String attributeDescription; private String attributeId; private String attributeTableName; private String attributeFieldName; private String attributeDescriptionFieldName; private String productTableName; private String productTableFieldName; private String productTupleName; private String productTupleFieldName; private String searchHelpId; October 2013 77 Development and Extension Guide – Application-Specific Information [...] public void initBackendObject(Properties backendParams, BackendBusinessObjectParams params) throws BackendException { attributeDescription = backendParams.getProperty(ATTR_DESCRIPTION); attributeId = backendParams.getProperty(ATTR_ID); searchHelpId = backendParams.getProperty(SEARCH_HELP_ID); attributeTableName = backendParams.getProperty(ATTR_TABLE_NAME); attributeFieldName = backendParams.getProperty(ATTR_FIELD_NAME); attributeDescriptionFieldName = backendParams.getProperty(ATTR_DESC_FIELD_NAME); productTableName = backendParams.getProperty(PRODUCT_TABLE_NAME); productTableFieldName = backendParams.getProperty(PRODUCT_TABLE_FIELD_NAME); productTupleName = backendParams.getProperty(PRODUCT_TUPLE_NAME); productTupleFieldName = backendParams.getProperty(PRODUCT_TUPLE_FIELD_NAME); } [...] } Please note that the various methods within the AttributeType are used for different aspects. Since the product view has a configuration and a runtime aspect, some methods are used in both aspects. Here is the list of methods used in the different aspects: Configuration Time o void setMdmConnector(...) o String getId() o String getDescription() o boolean isValueIdValid(...) o String getValueDescription(...) o String getSearchHelpName() o public Map<String, String> getHelpValuesSearchMapping(...) o public HelpValues getHelpValues(...) Runtime o void setMdmConnector(...) o String getId() o void processAttribute(...) 3.3.1.3 Enhancing backendobject-config.xml There are two backendobject-config.xml files used within the product view modules: sap/productviewmain/bo/backendobject-config.xml and sap.productview/wcbext/bo/backendobject-config.xml. The first one defines the product view backend objects used during the runtime and the second one defines the product view back-end objects used during the configuration time. The main difference between the two back-end object definitions is the defaultConnectionName type. The runtime uses a stateful connection whereas the configuration uses the stateless connection (using the technical user) to communicate with the CRM/ERP back end. Except the type of defaultConnectionName, the two files must be identical in terms of content and entries. Both backendobject-config.xml files need to be extended via the module extension concept. The following gives an example of adding an additional attribute called Distribution Channel Extended via the module extension concept that allows changes and addition of metadata content. In this case, both extensions of the backendobject-config.xml are identical since they connect to MDM and do not need to specify the back-end connection type. 78 October 2013 Development and Extension Guide – Application-Specific Information <?xml version="1.0" encoding="UTF-8"?> <backend xmlns="http://www.sap.com/wec/frw/tc/common/backendconfig" xmlns:wec="com.sap.wec.core.config" xmlns:xi="http://www.w3.org/2001/XInclude"> <businessObjects> <businessObject name="SimpleCRMMdMAttributeFactory" className="com.sap.wec.app.common.module.productview.backend.attribute.mdm.impl.SimpleAttributeF actory"> <params> <param name="AttributeType" value="CategoryCRM, SalesOrg, DCExt, DistChannel" /> </params> </businessObject> <businessObject name="SimpleERPMdMAttributeFactory" className="com.sap.wec.app.common.module.productview.backend.attribute.mdm.impl.SimpleAttributeF actory"> <params> <param name="AttributeType" value="MaterialClassificationCRM, SalesOrg, DCExt, DistChannel" /> </params> </businessObject> <businessObject name="DCExt" className="com.sap.wec.app.common.module.productview.backend.attribute.mdm.impl.GenericTupleWith LookupAttributeImpl"> <params> <param name="searchHelpId" value="DCExt_sh" /> <param name="attributeDescription" value="wcbext.productview.bo.attribute.distributionchannelExt" /> <param name="attributeId" value="DCE" /> <param name="attributeTableName" value="WECMDM_CRM_ERP_DIST_CHANS" /> <param name="attributeFieldName" value="WECMDM_CRM_ERP_DIST_CHAN" /> <param name="attributeDescriptionFieldName" value="WECMDM_CRM_ERP_DIST_CHAN_DESC" /> <param name="productTableName" value="WECMDM_CRM_ERP_PRD_CATALOG_ITMS" /> <param name="productTableFieldName" value="WECMDM_CRM_ERP_SALES_AREA" /> <param name="productTupleName" value="WECMDM_CRM_ERP_SALES_AREA_ATTRIBUTES" /> <param name="productTupleFieldName" value="WECMDM_CRM_ERP_DISTRIBUTION_CHANNEL" /> </params> </businessObject> </businessObjects> </backend> October 2013 79 Development and Extension Guide – Application-Specific Information Please note that in the above example, SimpleCRMMdMAttributeFactory and SimpleERPMdMAttributeFactory are enhanced to provide the additional DCExt value to the AttribyteType parameter. At the end of the file, there is the definition of the additional DCExt business object. The DCExt business object specifies as parameters all the information needed that will be injected into the business object when this one is initialized. Attribute Current Value Description searchHelpId DCExt_sh Name of the search help ID used as defined in the helpvalues-config.xml. This search help ID needs to be unique. attributeDescription wcbext.productview.bo.attribute.distributionchannelExt i18n ID of the description of this attribute attributeId DCE ID of the attribute. This value must be unique. It is used to identify the attribute type in the product view. productTableName WECMDM_CRM_ERP_PRD_CATALOG_ITMS This table represents the product catalog item table in MDM. productTableFieldNa WECMDM_CRM_ERP_SALES_AREA Thie field represents the field in the me table defined in the productTableName table. This field must be a tuple. productTupleName WECMDM_CRM_ERP_SALES_AREA_ATTRIBUTES Name of the tuple table that is referenced in the productTableFieldName productTupleFieldNa WECMDM_CRM_ERP_DISTRIBUTION_CHANNEL Name of the field within the tuple me table defined in productTupleName. This field must be of type lookup[flat] attributeTableName WECMDM_CRM_ERP_DIST_CHANS Name of the table that is referenced in the productTupleFieldName attributeFieldName WECMDM_CRM_ERP_DIST_CHAN Name of the column in the attributeTableName that will be used as ID in the product view attribute value attributeDescriptionF WECMDM_CRM_ERP_DIST_CHAN_DESC Name of the column in the ieldName attributeTableName that will be used as description in the product view attribute description 3.3.1.4 Enhancing productview/wcbext/bo/helpvalues-config.xml The following section shows the content of the helpvalues-config.xml that is used during the configuration time. This content enhances the current content via the module extension concept and defines (1) the search help and (2) the definition of its columns using the i18n text ID as defined in the xlf ressource file. One <helpValuesSearch> entry must be created for each new attribute type created. <helpValuesSearches xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:wec="com.sap.wec.core.config"> <helpValuesSearch name="DCExt_sh" type="simple" description="wcbext.productview.bo.attribute.distributionchannelExt" maxRow="10"> <method name="getHelpValues" type="businessObject" businessObjectName="ProductViewBO" /> <parameter name="id" description="wcbext.productview.bo.searchhelp.distchannelattribytevaluef4helpExt.id" valueDescriptionKey="wcbext.productview.bo.searchhelp.distchannelattribytevaluef4helpExt.id" /> <additionalParameter name="description" type="out" 80 October 2013 Development and Extension Guide – Application-Specific Information description="wcbext.productview.bo.searchhelp.distchannelattribytevaluef4helpExt.description" valueDescriptionKey="wcbext.productview.bo.searchhelp.distchannelattribytevaluef4helpExt.descrip tion" /> </helpValuesSearch> </helpValuesSearches> 3.3.1.5 Enhancing wcf_resources.xlf Since a new attribute has been defined, we need to enhance the content of the wcf_resources.xml file via the module extension concept. The following entry needs to be created in a new wcf_resources.xml file located under /src/customer/wcbext/bo : i18n ID i18n English Text wcbext.productview.bo.attribute.distributionchannelExt Distribution Channel Extended wcbext.productview.bo.searchhelp.distchannelattribytevaluef4helpExt.id Distribution Channel Extended ID wcbext.productview.bo.searchhelp.distchannelattribytevaluef4helpExt.description Distribution Channel Description Extended 3.3.1.6 Enhancing sap/productviewmain/md/metadata.xml and sap.productview/wcbext/metadata.xml The metadata of the productviewmain and wcbext module needs to be extended to provide the additional content that will refer to all the newly created xml metadata files. The sap/productviewmain/md/metadata.xml must be enhanced following the module extension concept in the src/customer/productviewmain/md/metadata.xml file. Here is an example of the content: <?xml version="1.0" encoding="UTF-8"?> <module xmlns="http://www.sap.com/wec/frw/tc/modules/metadata" xmlns:wec="com.sap.wec.core.config" lazyLoad="false" mainModule="false" moduleID="productviewmain" resourceBundlePrefix="productviewmain"> <moduleType>application</moduleType> <configForModule>productviewmain</configForModule> <config-file namespace="customer" part="bo" type="backend-objects">backendobject- config.xml</config-file> </module> The sap.productview/wcbext/metadata.xml must be enhanced following the module extension concept in the src/customer/wcbext/md/metadata.xml file. Here is an example of the content: <?xml version="1.0" encoding="UTF-8"?> <module xmlns="http://www.sap.com/wec/frw/tc/modules/metadata" xmlns:wec="com.sap.wec.core.config" lazyLoad="true" mainModule="false" moduleID="wcbext" resourceBundlePrefix="wcbext"> <moduleType>application</moduleType> <config-file namespace="customer" part="bo" type="backend-objects">backendobject- config.xml</config-file> <config-file namespace="customer" part="bo" type="helpvalues">helpvalues-config.xml</config- file> </module> October 2013 81 Development and Extension Guide – Application-Specific Information 3.3.2 Creating an Additional User Context for Product View The creation of a new user context in the product view requires the following: 1. Extending the product view modules wec/comm/mc/productview/bo wec/comm/mc/productviewmain/bo wec/comm/mc/productviewmain/md wec/comm/mc/productviewmain/dpu wec/comm/mc/wcbproductview/bo wec/comm/mc/wcbproductview/md wec/comm/mc/wcbproductview/dpu 2. Creating a new class implementing ContextType 3. Enhancing backendobject-config.xml files 4. Enhancing productview/wcbext/bo/helpvalues-config.xml 5. Enhancing wcf_resources.xlf 6. Enhancing sap/productviewmain/md/metadata.xml and sap.productview/wcbext/metadata.xml Please note that all the steps needed to create a new context are identical to those required for the creation of a new AttributeType, with the following differences: The new Java implementation needs to implement ContextType. Enhancement of the the two backendobject-config.xml to add a new business object entry that will point to the new implementation Enhancement of the the two backendobject-config.xml to enhance the business object ProductViewCRMBackendImpl and/or ProductViewERPBackendImpl with the new "Business Object" to the ContextType parameter 82 October 2013 Development and Extension Guide – Application-Specific Information 4 Product Configuration 4.1 Custom UI Rendering for Characteristics on Configuration UI This example shows you how to add a new UI type to the configuration UI. Goal: The standard is enhanced so that the characteristic Expected Number of Users is rendered with a stepper control instead of a simple input field. Standard: Enhancement: To achieve this, you have to enhance the ipc module, as shown in the following steps. 4.1.1 Adding a Custom Mapper for the Configuration UI UIElementMappers determine which characteristics are rendered in which format on the UI. To enhance this, an additional mapper is introduced. This is accomplished via the UIElementMapperFactory. To use a custom factory for the mappers, the factory-config.xml has to be adapted: <factoryClass name="com.sap.wec.app.common.module.ipc.ui.dynamic.ui.interf.UIElementMapperFactory" singleton="false" className="com.customer.wec.app.common.module.ipc.ui.dynamic.ui.impl.CustUIElementMapperFactoryI mpl" /> Now, the class CustUIElementMapperFactoryImpl can enhance the existing implementation: public class CustUIElementMapperFactoryImpl extends UIElementMapperFactoryImpl { @Override public void registerUIElementMappers() { CustNumericStepperForNumberOfUsersMapperImpl numericStepperMapper = new CustNumericStepperForNumberOfUsersMapperImpl(); registerUIElementMapper(numericStepperMapper); super.registerUIElementMappers(); } } October 2013 83 Development and Extension Guide – Application-Specific Information The order of the mappers is very important. The first applicable mapper is used. Therefore, the new mapper is registered BEFORE super.rigisterUIElementMappers() is called. 4.1.2 Registering a New UI Type In this example, we do not want to change the data or behavior of the UI element, only the rendering. Therefore, the new mapper changes only the UI type to be used for rendering. Furthermore, we have to ensure that the mapper in our example is only applicable if the characteristic is Expected Number of Users. public class CustNumericStepperForNumberOfUsersMapperImpl extends InputUIElementMapperImpl { @Override public boolean isMapperForCharacteristic(Characteristic cstic, boolean isExpandedOnUI)throws BusinessObjectException { boolean isNumberOfUsers = cstic.getName().equals("EXP_NO_USERS"); return isNumberOfUsers; } @Override public void initUIElement(EntryField uiElement,boolean validateCharacteristicOnline) throws BusinessObjectException { super.initUIElement(uiElement, cstic, validateCharacteristicOnline); uiElement.setUiType("uitype_numeric_stepper"); } } Two more steps are needed to register the new custom UI type: 1. Register a renderer class for the used string constant (in this case, uitype_numeric_stepper). public class CustUIRendererManager extends IPCUIRendererManager { private static final UITypeRenderer UI_TYPE_RENDERER_NUMERIC_STEPPER = new CustUITypeRendererNumericStepper(); private static final String UI_TYPE_NUMERIC_STEPPER = "uitype_numeric_stepper"; @Override public UITypeRenderer getUIRenderer(String uiType) { UITypeRenderer uiRenderer; if (UI_TYPE_NUMERIC_STEPPER.equals(uiType)) { uiRenderer = UI_TYPE_RENDERER_NUMERIC_STEPPER; }else { uiRenderer = super.getUIRenderer(uiType); } return uiRenderer; } } 84 October 2013 Development and Extension Guide – Application-Specific Information 2. Define a renderer class that defines which UI include is used. public class CustUITypeRendererNumericStepper implements UITypeRenderer { private static String XHTML_INCLUDE_NAME = "uitype_numeric_stepper"; @Override public String getXHTMLIncludeName() { return UITypeRendererHandler.getXHTMLInclude(XHTML_INCLUDE_NAME); } } 4.1.3 Adding the Custom XHTML Fragment Finally, we can add the XHTML fragment to be used for the introduced UI type and add the mapping between this XHTML file and the UI include name. To enhance the mapping of the UI includes to the XHTML file, we have to define a custom config file in the metadata.xml file of the md part. <config-file namespace="customer" part="ui" type="dynamic-ui-config">dynamicXHTMLInclude- config.xml</config-file> Then the mapping for the newly created XHTML file can be added in dynamicXHTMLInclude-config.xml. <dynamicXHTMLIncludes xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xml="http://www.w3.org/XML/1998/namespace"> <xhtmlinclude name ="uitype_numeric_stepper" value="/resources/customer/ipc/includes/dynUI/uiTypeNumericStepper.xhtml" ></xhtmlinclude > </dynamicXHTMLIncludes> October 2013 85 Development and Extension Guide – Application-Specific Information 4.2 Shopping Cart Summary with Pricing on Configuration UI This example shows how the layout of the configuration UI can be changed to integrate a shopping cart summary view. The first image shows the configuration UI before, and the second one after, the enhancement. 86 October 2013 Development and Extension Guide – Application-Specific Information 4.2.1 Changing the Layout of the Configuration UI from 2-Column-Navigation to 2-Column-Sidebar To use a different layout, you need to create the new page configUIWithSidebar.xhtml. It is quite similar compared to the original configUI.xhtml page. It will have a content area as well, but instead of a navigation area, it defines a sidebar. <ui:define name="baseExension"> <wec:form id="fC"> <ui:decorate template="#{wecf:getPageLayout('ipc','configUIWithSidebar')}"> <ui:define name="content" > <wcf:pageArea areaName="content" id="paC"/> </ui:define> <ui:define name="sidebar" > <wcf:pageArea areaName="sidebar" id="paS"/> </ui:define> </ui:decorate> </wec:form> </ui:define> With the EL-Expression #{wecf:getPageLayout('ipc','configUIWithSidebar')} you make a reference to the ui- repository.xml file, where you need to declare the new page and assign the predefined 2columnSidebar layout. October 2013 87 Development and Extension Guide – Application-Specific Information <Page defaultLayout="2columnSidebar" name="configUIWithSidebar" extends="refBasePage" contentArea="content" menu="shop" ownLayoutUsed="true"> <Layout name="2columnSidebar"/> <Area defaultInclude="configUIContentIncl" name="content"/> <Area defaultInclude="custSidebarIncl" name="sidebar"/> </Page> The configuration UI is accessed using the navigation target configUI. So, we overwrite the standard target by defining it in the ui-repository.xml file, but letting it point to the new page. <NavigationTarget name="configUI" targetComposition="Page:configUIWithSidebar[content=configUIContentIncl,sidebar=custSidebarIncl] "/> 4.2.2 Including the Mini Cart Preview in the Sidebar Using Module Interfacing The new page and navigation target reference two UI includes. The configUIContentIncl include is just the standard SAP include containing the main part of the configuration UI where you can change the configuration characteristics. The custSidebarIncl include is new, so it needs to be declared in the ui-repository.xml file as well. <UIInclude name="custSidebarIncl"/> The corresponding file custSidebarIncl.xhtml just contains the single composite component ipc:custSidebar. <ipc:custSidebar id="cSB"/> The composite component is new as well, and will include the mini cart preview using a module interface provided by the salestransaction module. So the custSidebar.xthml file will look like this: <cc:implementation> <wcf:moduleInterface id="mIbp" name="com.sap.sales.Checkout" viewComponent="minibasketpreview" /> </cc:implementation> Due to the simplicity of the view, there is no need to declare a view handler. The module interface already exists, since the mini cart preview is already used within the checkout, so finally only the dependency on the module interface should be added to metadata.xml, if not present yet. <interfaceDependency dependencyType="hard" interfaceName="com.sap.sales.Checkout" namespace="sap" /> 4.2.3 Adapting the Re-Render IDs Since we removed the old navigation area from the configuration UI, it is necessary to adapt the list of re-render IDs that will identify the components to be re-rendered on AJAX requests. The standard list contains IDs that refer to the old navigation bar. Referring to non-existent IDs will lead to a runtime exception. In addition, you need to add the new sidebar to the re-render ID list, so you can see price changes in the cart summary when a pricing-relevant characteristic is changed. The re-render IDs for the configuration UI are defined in the dynamic UI inbound interface, which is implemented by class DynamicUIInboundImpl. Since this class is instantiated using the generic factory we can easily exchange it with a customer implementation using the factory-config.xml file. 88 October 2013 Development and Extension Guide – Application-Specific Information <factoryClass singleton="false" name="com.sap.wec.app.common.module.ipc.ui.view.interf.DynamicUiInboundInternal" className="com.customer.wec.app.common.module.ipc.ui.view.impl.CustDynamicUiInboundImpl" /> The class CustDynamicUiInboundImpl extends the SAP implementation and looks like the example below. public class CustDynamicUiInboundImpl extends DynamicUiInboundImpl { public static final String RERENDER_ID_CUSTSIDEBAR = "fC:pg2ndColumn"; public CustDynamicUiInboundImpl() { super(); // remove all but first ID String id = reRenderIds.get(0); reRenderIds.clear(); reRenderIds.add(id); reRenderIds.add(RERENDER_ID_CUSTSIDEBAR); } } The re-render ID list is filled in the constructor of the super implementation. The first ID refers to the header, so we keep it. The other IDs refer to the navigation bar, so we discard them. Instead, we add an ID to re-render the entire new sidebar. October 2013 89 Development and Extension Guide – Application-Specific Information 4.3 Removal of “Not Specified” Option on Configuration UI This example shows how the layout of the configuration UI can be changed when the default option Not Specified for radio button lists is removed. The first image shows the configuration UI before, and the second one after, the enhancement. 1. Create a class that inherits from RadioButtonUIElementMapperImpl (for example CustRadioButtonUIElementMapperImpl). 2. Register the class (for example CustRadioButtonUIElementMapperImpl) in the factory-config.xml file as described in the general enhancement concepts. 3. Override the updateUIElement method to call updateAllowedValues with parameter includeNilValue set to false. package com.customer.wec.app.common.module.ipc.ui.dynamic.ui.impl; import com.sap.wec.app.common.module.ipc.businessobject.interf.Characteristic; import com.sap.wec.app.common.module.ipc.ui.dynamic.ui.impl.RadioButtonUIElementMapperImpl; import com.sap.wec.tc.core.businessobject.BusinessObjectException; import com.sap.wec.tc.core.ui.model.interf.EntryField; public class CustRadioButtonUIElementMapperImpl extends RadioButtonUIElementMapperImpl { @Override public void updateUIElement(EntryField uiElement, Characteristic cstic, boolean isCheckMode) throws BusinessObjectException { super.updateUIElement(uiElement, cstic, isCheckMode); if (cstic.isDomainConstrained() || cstic.allowsAdditionalValues()) { updateAllowedValues(uiElement, cstic, false); } } } 90 October 2013 Development and Extension Guide – Application-Specific Information 4.4 Reference Characteristics You can use reference characteristics to automatically apply certain values from the environment as context information, or to copy values to the environment, during runtime of product configuration with the configuration engine. You can use the dependency to then include these values in rules. This extension example describes how to set reference characteristics out of SAP Web Channel Experience Management. Note that several standard reference characteristics are already set. Standard reference characteristics supported in the SAP CRM deployment scenario: BUT000-PARTNER BUT000-AG VBAK-KUNNR VBPA_AG-KUNNR VBPA_AG-LAND1 VBPA_RG-KUNNR VBPA_RG-LAND1 VBAK-VKORG VBAK-VTWEG VBAK-SPART VBAK-ERDAT VBAP-KWMENG COMM_PRODUCT-PRODUCT_ID VBAP-MATNR Standard reference characteristics supported in the SAP ERP deployment scenario: VBAK-KUNNR VBPA_AG-KUNNR VBPA_AG-LAND1 VBPA_RG-KUNNR VBPA_RG-LAND1 VBAK-VKORG VBAK-VTWEG VBAK-SPART VBAK-ERDAT VBAP-KWMENG VBAP-MATNR For more information about reference characteristics, see http://help.sap.com/saphelp_crm70/helpdata/en/47/68c3aedc6e17f9e10000000a42189c/frameset.htm. October 2013 91 Development and Extension Guide – Application-Specific Information Proceed as follows: 1. Create customer module extension for module ipc. 92 October 2013 Development and Extension Guide – Application-Specific Information 2. Add newly created custom module to custom Web Channel application (maintain dependency to DPU part). 3. Maintain development component dependencies and public parts for the created custom modules. o Dependencies: o Public Parts: 4. Create file businessobject-config.xml. October 2013 93 Development and Extension Guide – Application-Specific Information <?xml version="1.0" encoding="UTF-8"?> <businessObjects xmlns="http://www.sap.com/wec/frw/tc/common/boconfig"> <businessObject name="ReferenceCsticsProvider" className="com.customer.wec.app.common.module.ipc.businessobject.impl.CustReference CsticsProviderImpl"> </businessObject> </businessObjects> 5. Add businessobject-config.xml to metadata.xml. 94 October 2013 Development and Extension Guide – Application-Specific Information File: metadata.xml <?xml version="1.0" encoding="UTF-8"?> <module xmlns="http://www.sap.com/wec/frw/tc/modules/metadata" lazyLoad="true" mainModule="false" moduleID="ipc"> <moduleType>application</moduleType> <configForModule>ipc</configForModule> <config-file namespace="customer" part="bo" type="bo-config">businessobject- config.xml</config-file> </module> 6. Create custom class for the above mentioned business object and implement your own version of method setReference. Example: package com.customer.wec.app.common.module.ipc.businessobject.impl; import java.util.Map; import com.sap.wec.app.common.module.ipc.businessobject.integration.impl.ReferenceCsticsProviderI mpl; import com.sap.wec.app.common.module.ipc.businessobject.integration.interf.ReferenceCsticsProvide r; import com.sap.wec.app.common.module.ipc.businessobject.interf.IPCItemProperties; import com.sap.wec.tc.core.businessobject.BusinessObjectException; public class CustReferenceCsticsProviderImpl extends ReferenceCsticsProviderImpl implements ReferenceCsticsProvider{ @Override public void setReferenceCstics(IPCItemProperties props) throws BusinessObjectException { super.setReferenceCstics(props); Map<String, String> contextAttribs = props.getContext(); October 2013 95 Development and Extension Guide – Application-Specific Information contextAttribs.put("VBAK-AUART", "TA"); props.setContext(contextAttribs); } } Note that in case of additional back-end calls or back-end specifics, it is probably better to extend the respective back-end classes of class ReferenceCsticsProviderImpl and implement your custom version of method setReferenceCstics there. 96 October 2013 Development and Extension Guide – Application-Specific Information 5 Shopping Cart and Order 5.1 Custom Attributes You can display new fields on the Web shop UI or change the value of these fields. Note that the extensibility concept provided by the back end is illustrated using the SAP ERP back end using the enhancement capabilities of the Lean Order API (LO API). The back-end independent parts are also valid for a Web shop using the SAP CRM back end. 5.1.1 Enhancing Fields in the Back End For an extensive description of the extension concept provided by the LO API, see the attachment to SAP Note 1224179. For the following example, the first two subchapters of the Enhancement Options chapter were followed. We defined an append structure having the fields BSTKD_E and BSTDK_E. This was defined for TDS_HEAD_COMV. Afterwards, the mapping between the append structure fields and the fields in the business logic were defined in LORD_MAPPING table. Note Extensions using subobjects HDDATAA, HDDATAB, IDATAA, and IDATAB are not supported using the technique we describe in this example (see chapter Enhanceable Lean Order Objects in the attachment to SAP Note 1224179). For supporting the reading of the fields mentioned above using the LO API, it is enough for you to enhance TDS_HEAD_COMV and maintain LORD_MAPPING. In order to support editing and maintainance of the fields, an append structure must be added to TDS_HEAD_COMC and an implementation should be provided for the BADI_LORD_DO_PAI in order to trigger the processing of fields after input. For more information, see the following code: method IF_BADI_LORD_DO_PAI~ADD_SUPPLY_LIST. data: ls_supply type tds_field_supply. if iv_object_id eq 'HEAD'. if iv_module eq 'VBAK_BEARBEITEN'. ls_supply-field = 'ZZ_BSTKD_E'. append ls_supply to ct_supply. ls_supply-field = 'ZZ_BSTDK_E'. append ls_supply to ct_supply. endif. October 2013 97 Development and Extension Guide – Application-Specific Information 5.1.2 Displaying Custom Fields on the UI To make additional fields from the back end available to Web shop customers, you must first identify the view where the new fields are supposed to be shown. It most often helps to add &wec-debug=true to the current URL and to refresh the page to see the actual page and view structure. For example, see the following screenshot of the order overview page: Suppose that we want to add new fields on order header level. We know from the debugging information displayed that we need to work with view richheader-readonly.xhtml to display new fields on the UI. Now the SAP delivered view will be copied into the UI part of the extension module. Assuming the extension name space is customer, it is located in the following path: ..\src\META-INF\resources\customer\salestransactions\components\richheader-readonly.xhtml 98 October 2013 Development and Extension Guide – Application-Specific Information You need to modify the view by adding the necessary JSF components for display. For example, an extension to the view might look like the following code: <wec:comment value="WEC Extension Purchase Order Nr"/> <wec:outputLabel for="txtPurchOrdNo" id="oLbPurchOrdNo" value="#{i18n['sapsalestransactions.ui.purchase.number']}"/> <wec:outputText id="txtPurchOrdNo" styleClass="fw-form-gridcol3" value="#{cc.vch.salesDocumentHeaderBean.shippingPurchaseOrderNo}"/> <wec:comment value="WEC Extension Purchase Order Date"/> <wec:outputLabel for="txtPurchOrdDate" id="oLbPurchOrdDate" rendered="#{cc.vch.salesDocumentHeaderBean.shippingPurchaseOrderDateAvailable}" value="#{i18n['sapsalestransactions.ui.purchase.date']}"/> <wec:outputText id="txtPurchOrdDate" rendered="#{cc.vch.salesDocumentHeaderBean.shippingPurchaseOrderDateAvailable}" styleClass="fw-form-gridcol3" value="#{cc.vch.salesDocumentHeaderBean.shippingPurchaseOrderDate}"> <wec:convertDateShort4/> </wec:outputText> The new view needs to be present in the ui-repository of the extension module, as shown in the following code: <ViewComponent name="richheader-readonly" componentHandlerClassName= "com.sap.wec.app.esales.module.transaction.ui.viewhandler.SalesDocumentHeaderViewHandlerImpl" /> The ui-repository itself must be registered for extension in the module metadata.xml, as shown in the following code: <?xml version="1.0" encoding="UTF-8"?> <module xmlns="http://www.sap.com/wec/frw/tc/modules/metadata" lazyLoad="true" mainModule="false" moduleID="salestransactions"> <moduleType>application</moduleType> <configForModule>salestransactions</configForModule> <config-file namespace="customer" part="ui" type="ui-repository">ui-repository.xml</config- file> Metadata.xml resides in the md part of the module while ui-repository.xml resides in the ui part of the module under the folders with the names formatted as follows: <module namespace>.<module id>.<module part>. These can be found in the module.properties. In order for the system to display the fields in the view, the corresponding bean must know about them. Therefore, new getter methods will be added to the bean, which will extend the bean implementation provided by SAP. Recommendation Use typed attributes for the extensions on the level of the BO beans in the UI layer because this leads to views that are easier to understand. We sub-class the respective UI bean and implement typed attributes for the new attributes. October 2013 99 Development and Extension Guide – Application-Specific Information The following shows a code snippet of the extended BO bean, which should support the new purchasing attributes: public class CustHeaderBeanImpl extends SalesDocumentHeaderBeanImpl { private static final String EXT_FIELD_SHIPPING_PURCHASE_ORDER_NUMBER = "ZZ_BSTKD_E"; public String getShippingPurchaseOrderNo() { String shippingPurchaseOrderNo = ""; if (getBO().getExtensionData( EXT_FIELD_SHIPPING_PURCHASE_ORDER_NUMBER) != null) { shippingPurchaseOrderNo = (String) getBO().getExtensionData( EXT_FIELD_SHIPPING_PURCHASE_ORDER_NUMBER); } return shippingPurchaseOrderNo; } public Date getShippingPurchaseOrderDate() { Object extensionObject = getBO().getExtensionData( EXT_FIELD_SHIPPING_PURCHASE_DATE); if (extensionObject != null){ String dateAsString = (String) extensionObject; if (!dateAsString.isEmpty() && (!dateAsString.equals("00000000"))){ Date shippingPurchaseOrderDate = ConversionHelper.convertDateStringToDate(dateAsString); return shippingPurchaseOrderDate; } } return new Date(System.currentTimeMillis()); } Note We convert the date string into a Java date in the UI layer, which does not match the standard pattern, as standard date or currency amount attributes are converted in the back-end layer and are then available as typed attributes in bo and ui. But as LO-API provides the extension attributes in character format and WCEM puts all extension attributes directly into the bo extensions, this approach is appropriate for extension attributes. By declaring the implementation class in the factory-config.xml, you ensure that the new bean will be in place and used at runtime instead of the default implementation provided. Factory-config.xml will be linked in the metadata.xml in the same way as the ui-repository, as shown in the following code: <factory xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:wec="com.sap.wec.core.config"> <factoryClass name= "com.sap.wec.app.esales.module.transaction.ui.beans.interf.SalesDocumentHeaderBean" singleton="false" className= "com.customer.wec.app.esales.module.salestransactions.ui.beans.impl.CustHeaderBeanImpl" /> </factory> 100 October 2013 Development and Extension Guide – Application-Specific Information 5.1.3 Adding Resource Keys for New Labels on the Web Shop UI The resource keys are used as shown below and defined in the wcf_resources.xlf file in the ui part of the module (the salestransactions module, in this example). The file must be created under the folder with the name <module namespace>.<module name>.ui, as shown in the figure below: The prefix of the resource key must be the same as defined in the metadata.xml file of the salestransactions module as shown in the following code: <module xmlns="http://www.sap.com/wec/frw/tc/modules/metadata" lazyLoad="true" mainModule="false" moduleID="salestransactions" resourceBundlePrefix="sapsalestransactions" standalone="true"> <wec:comment value="WEC Extension Purchase Order Nr" /> <wec:outputLabel id="oLbPurchOrdNo" value="#{i18n\['sapsalestransactions.ui.purchase.number'\]}" for="txtPurchOrdNo" /> 5.1.4 Reading Custom Fields from the Back End In order to fill the fields that are supposed to be shown with values, you must extend the back end. You need to let LO-API know that it should provide us the additional attributes. In this example, we want to display the purchase order number BSTKD_E and the purchase order date BSTDK_E, in addition. To do this, a new implementation of ERPLO_APICustomerExits is required, which should subclass com.sap.wec.app.esales.module.transaction.salesdocument.backend.impl.erp.strategy. October 2013 101 Development and Extension Guide – Application-Specific Information The class implementation could look like the following code: public class CustomerExits extends ERPLO_APICustomerExitsImpl { public Map<LrdFieldExtension.FieldType, LrdFieldExtension> customerExitGetExtensionFields() { if (extensionFields != null) { return extensionFields; } else { extensionFields = new HashMap<LrdFieldExtension.FieldType, LrdFieldExtension>(); } // Register the new attributes for reading // Both attributes are on header level LrdFieldExtension headerComVExtension = new LrdFieldExtension( LrdFieldExtension.FieldType.HeadComV); headerComVExtension.addField("ZZ_BSTKD_E"); headerComVExtension.addField("ZZ_BSTDK_E"); extensionFields.put(LrdFieldExtension.FieldType.HeadComV, headerComVExtension); return extensionFields; } Additionally, the respective entries must be made in the factory-config.xml file to register our CustomerExits class. This class and the factory-config.xml file are placed in the bo part of the module, as shown in the following code: <factoryClass name="com.sap.wec.app.esales.module.transaction. salesdocument.backend.interf.erp.strategy.ERPLO_APICustomerExits" singleton="false" className="com.customer.wec.app.esales.module.salestransactions. backend.impl.erp.strategy.CustomerExits" /> The application automatically puts these extensions into the extension map of the sales document header or the item. Therefore, it is not required to handle these extensions in the business object layer. Of course, there might be cases where such extensions could also influence the business objects (for example, if other attributes depend on them). In these cases, the business objects also need to be changed. 102 October 2013 Development and Extension Guide – Application-Specific Information 5.1.5 Writing Custom Fields to the Back End You can enhance the checkout process with an additional step. The following figure shows the checkout step for purchase information: To set the values of the fields for purchase order number and purchase date, you must implement the setter methods in the view handler of the checkout step for purchase information, as shown in the following code: public class PurchaseDataExpandedViewHandlerImpl extends StepElementBaseViewHandlerImpl { public void setShippingPurchaseOrderNo(String shippingPurchaseOrderNo) { CustHeaderBeanImpl header =(CustHeaderBeanImpl)getSalesDocumentHeaderBean(); header.setShippingPurchaseOrderNo(shippingPurchaseOrderNo); } public void setShippingPurchaseOrderDate(Date shippingPurchaseOrderDate) { CustHeaderBeanImpl header =(CustHeaderBeanImpl)getSalesDocumentHeaderBean(); header.setShippingPurchaseOrderDate(shippingPurchaseOrderDate); } ... October 2013 103 Development and Extension Guide – Application-Specific Information The setters called by CustHeaderBeanImpl set the values introduced on the Web shop UI to the extension map of the business object, as shown in the following code: public class CustHeaderBeanImpl extends SalesDocumentHeaderBeanImpl { public void setShippingPurchaseOrderNo(String purchaseOrderNo) { getBO().addExtensionData(EXT_FIELD_SHIPPING_PURCHASE_ORDER_NUMBER, purchaseOrderNo); } public void setShippingPurchaseOrderDate(Date purchaseOrderDate) { String dateString = ConversionHelper.convertDateToDateString(purchaseOrderDate); getBO().addExtensionData(EXT_FIELD_SHIPPING_PURCHASE_DATE, dateString); } The Lean Order API knows about the fields which are marked for back-end enhancement. For more information, see Reading Custom Fields from the Back End. Note Due to the way the Lean Order API handles date attributes, date conversion does not correspond to the pattern used for handling dates in SAP Web Channel Experience Management. 5.1.6 Extending the Checkout UI Checkout Implementation You must define the look of the new step in checkout. That is, which view is shown in the collapsed mode, which view is shown in expanded mode, or if the data is validated (that is, the sales document is updated) when Web shop customers choose the Continue pushbutton. This is done in the checkoutProcessMetadata.xml file. This definition is the basis for creating the checkoutProcessConfig.xml, which you upload using Web Channel Builder. <CheckoutMetadataConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="checkoutProcessMetadataSchema.xsd"> <!-- StepElements repository --> <StepElementConfiguration> <StepElement ID="SE_CUSTPURCHASEDATA" collapsedViewName="/checkout/includes/purchaseCollapsedIncl.xhtml" expandedViewName="/checkout/includes/purchaseExpandedIncl.xhtml" orderConfirmationViewName="" UITitle="checkout.ui.stepelement.custelement.uititle" validatorClass= "com.customer.wec.app.ecom.module.checkout.ui.stepelements.validator.PurchaseDataValidator" /> </StepElementConfiguration> <ProcessTypes> <ProcessType ID="Sales"> ... <!-- Purchase Data --> <allowedStepElement ID="SE_CUSTPURCHASEDATA" /> ... </allowedStepGroup> ... 104 October 2013 Development and Extension Guide – Application-Specific Information The CheckoutProcessMetadata.xml file must be linked in the metadata.xml file of the extended Checkout Process Configuration module, as shown in the following code: <?xml version="1.0" encoding="UTF-8"?> <module xmlns="http://www.sap.com/wec/frw/tc/modules/metadata" lazyLoad="true" mainModule="false" moduleID="com.sap.checkout.processconfig"> <moduleType>application</moduleType> <configForModule>com.sap.checkout.processconfig</configForModule> <config-file namespace="customer" part="md" type="checkoutconfig"> checkoutProcessMetadata.xml </config-file> ... After defining these two configuration files in the md part of the checkout.processconfig module, you can define the views in the checkout module. You need to define the two views and includes and put them in the resources folder of the checkout module. For example, the folder structure might look like the following figure: For these two views the corresponding view handlers must also be defined in the ui part of the customer checkout module. The view handlers must be defined in the ui-repository.xml file, as shown in the following code: ... <ViewComponent name="purchaseCollapsed" componentHandlerClassName="com.customer..." /> <ViewComponent name="purchaseExpanded" componentHandlerClassName="com.customer..." /> ... October 2013 105 Development and Extension Guide – Application-Specific Information In order to make sure that the sales document is updated when Web shop customers choose the Continue pushbutton (meaning the values entered are sent to the back end), a validator must be implemented as shown in the following code: public class PurchaseDataValidator extends BaseValidator { public PurchaseDataValidator() { super(); } @Override public boolean isUpdateNeeded() { return true; Checkout Customizing You need to upload a changed process configuration in the checkout.processconfig module of Web Channel Builder. The new step might look like the following code: <Step Description="" ID="S_CUST" STEPGROUP_ID="SG_DETAILS" UITitle="checkout.ui.step.custstep.uititle"> <StepElementRef Description="" ID="SE_CUSTPURCHASEDATA" UITitle="checkout.ui.stepelement.custelement.uititle" showOnOrderConfirm="false" /> </Step> Note that the ID of the step element must match the previously defined metadata. 106 October 2013 Development and Extension Guide – Application-Specific Information 5.2 Additional Fields Read from ERP SD via LO-API This example shows how to read additional information from LO-API. Assume that for product substitution, you also want to display the substitution reason along with the information message. This information is not considered in WCEM standard. 5.2.1 Extending Module and Registering Extensions You need to extend the salestransactions module in your namespace. Since this extension affects the back-end layer, the bo part is necessary. The extension is done in a custom extension of com.sap.wec.app.esales.module.transaction.salesdocument.backend.impl.erp.strategy.GetAllStrategyERP605, which is the class that handles the sales document read process. To instantiate a new strategy implementation, a new StragegyFactory is needed, which looks like this: public class CustStrategyFactory extends StrategyFactoryERP { @Override public GetAllStrategy createGetAllStrategy() { return new CustGetAllStrategyERP(); } } October 2013 107 Development and Extension Guide – Application-Specific Information Register this factory in factory-config.xml as follows: ... <factoryClass name="STStrategyFactoryERP" singleton="false" className="com.customer.wec.app.esales.module.transaction.salesdocument. backend.impl.erp.strategy.CustStrategyFactory" /> ... And state that factory-config.xml is extended. Excerpt from metadata.xml: ... <config-file namespace="customer" part="bo" type="factory-config">factory-config.xml</config- file> ... 5.2.2 Reading Substitution Reason and Attaching it to New Message You need to perform two steps: Reading the substitution reason from structure TDS_RFC_ITEM_COMR, and later on enriching the information message that explains the substitution. The resource key for the new message sapsalestransactions.erp.ui.rfc.newmsg needs to be maintained outside CustGelAllStrategyERP. The coding of CustGetAllStrategyERP looks like this: @Override protected void mapItemComR(....) { super.mapItemComR(salesDoc, ttItemComR, shop, subTotalItemFreight, setIpcPriceAttributes, item, itemsPriceAttribMap, itemVariantMap, boBaseR3Lrd); // now check for the substitution reason and store it for later processing String substitutionReason = ttItemComR.getString("SUGRD_T"); item.addExtensionData(SUBST_REASON, substitutionReason); } @Override public BackendCallResult execute(....) throws BackendException { BackendCallResult result = super.execute(backendState, salesDocument, itemBuffer, readParams, cn, cardType, creditCardStrategy); exchangeMessage(salesDocument); return result; } private void exchangeMessage(SalesDocument salesDocument) { String resourceKey = "sapsalestransactions.erp.ui.rfc.messages.label.V2167"; //check if the document carries the warning message for substitution MessageList messageList = salesDocument.getOwnMessageList(); 108 October 2013 Development and Extension Guide – Application-Specific Information MessageList newMessages = new MessageList(); for (Message message: messageList){ if (message.getResourceKey().equals(resourceKey)){ String productId = message.getResourceArgs()[0]; String newProduct = message.getResourceArgs()[1]; String substReason = getReason(newProduct, salesDocument); String[] args = new String[]{productId,newProduct,substReason}; Message newMessage = new Message(Message.INFO, "sapsalestransactions.erp.ui.rfc.newmsg", args, null); newMessages.add(newMessage); } } messageList.remove(resourceKey); messageList.add(newMessages); } private String getReason(String newProduct, SalesDocument salesDocument) { for (Item item: salesDocument.getItemList()){ if (item.getProductId().equals(newProduct)){ return (String) item.getExtensionData(SUBST_REASON); } } return null; } October 2013 109 Development and Extension Guide – Application-Specific Information 5.3 Shopping Cart - User Interface You can enhance the shopping cart UI from the following perspectives: SAP CRM (based on applying the Application Enhancement Tool) Java (based on the SAP module enhancement concept) 5.3.1 Adding a New Field Using the AET In SAP CRM, you can enhance CRM sales orders by adding a new field (for example, a CRM Order Extension field) to the General Data area of the sales order application with the Application Enhancement Tool (AET), as follows: 1. To enable the configuration mode, choose Personalize Settings and enable the configuration mode as shown in the following figures: 2. Switch to configuration mode by choosing the Show Configuration Mode pushbutton, as highlighted in the following figure: 110 October 2013 Development and Extension Guide – Application-Specific Information 3. To add the CRM Order Extension field to the General Data area of the sales order application, select the General Data area as shown in the following figure: After you have selected the General Data area, the system displays the UI Configuration Tool. October 2013 111 Development and Extension Guide – Application-Specific Information 4. To start the AET, choose the Create Field pushbutton as highlighted in the figure below: 112 October 2013 Development and Extension Guide – Application-Specific Information 5. In the AET, select the BO part that you want to enhance (in this example, the ORDERADMIN_H part), as shown in the following figure: October 2013 113 Development and Extension Guide – Application-Specific Information 6. On the Field Details – Webpage Dialog screen, enter field details (for example, field label, field type, and length), as shown in the following figure: 7. To go back to the configuration overview, choose the Back pushbutton. 8. To trigger the generation process, choose the Save and Generate pushbutton. The system creates the new field, enhances the relevant external interfaces (for example, if you select the BW Reporting checkbox, the system modifies the data source and the BI extractor), adds the structural changes and the enhancement metadata to a transport request, and starts the activation process. 114 October 2013 Development and Extension Guide – Application-Specific Information 9. To show the available fields in the view, choose the Show Available Fields pushbutton highlighted in the following figure: October 2013 115 Development and Extension Guide – Application-Specific Information 10. To add the CRM Order Extension field to the configuration view, select the field and choose the Add Field pushbutton highlighted in the following figure: 116 October 2013 Development and Extension Guide – Application-Specific Information 11. To go back to the sales order application, choose the Save and Close pushbutton. The following figure shows the new CRM Order Extension field on the UI: 5.3.2 Adding A New Field Using Java You can add a new field (in this example, the CRM Customer Extension Field) to the to the Web shop UI, as shown in the following figure: The content of this field must be passed to the back end by a generic BO feature. In this example, the header view of the shopping cart (called leanbasketheader.xhtml) is enhanced by one additional field as displayed in the figure above. October 2013 117 Development and Extension Guide – Application-Specific Information Create customer DCs in the customer namespace according to the general SAP Web Channel Experience Management enhancement concept. The following customer specific DCs need to be created: MD BO UI You need these DCs in the customer namespace as shown in the following figure: Note that all DCs are included in the corresponding deployment unit. UI Development Component The ui-repository.xml file must include the corresponding enhanced view component (called leanbasketheader) as shown in the following code: <?xml version="1.0" encoding="UTF-8" standalone="no"?> <UIRepository xmlns="http://www.sap.com/wec/wcf/viewcomposition/ui-repository" xmlns:wec="com.sap.wec.core.config" module="salestransactions"> <ViewComponent name="leanbasketheader" componentHandlerClassName="com.sap.wec.app.esales.module.transaction.ui.viewhandler.LeanBasketHe aderViewHandlerImpl" /> </UIRepository> Note In this example the standard bean is used. If an enhancement of the bean is applied as well, then the corresponding bean must also be implemented in the extension DC part. 118 October 2013 Development and Extension Guide – Application-Specific Information A customer-specific view component must be created to include the customer-specific fields. In this example, it is called the same as the original component (that is, leanbasketheader.xhtml) and is shown in the structure in the following figure: The following figure shows how the customer-specific field is implemented in the customer-specific view component leanbasketheader.xhtml. You can use the original view as a template. The new field ZZORDERADM_H6801 (as an enhancement of structure ORDERADM_H) is added to the original view leanbasketheader.xhtml, as highlighted in the figure below: October 2013 119 Development and Extension Guide – Application-Specific Information MD Development Component The metadata.xml file is part of the MD DC, as shown in the following figure: The metadata.xml file needs to include the entries shown in the following figure: 120 October 2013 Development and Extension Guide – Application-Specific Information BO Development Component In the customer-specific BO DC, you need to create an extension mapper class called ExtMapperImpl that extends class ExtensionMapperImpl (to declare the new fields), as shown in the following figure: In this example, field ZZORDERADM_H6801 in structure ORDERADM_H is added in the following code (for more information, see Adding a New Field Using the AET): package com.customer.wec.app.esales.module.salestransactions.backend.impl.crm.strategy; import com.sap.conn.jco.JCoFunction; import com.sap.wec.app.esales.module.transaction.businessobject.interf.SalesDocument; import com.sap.wec.app.esales.module.transaction.salesdocument.backend.impl.crm.mapper.ExtensionMapperI mpl; public class ExtMapperImpl extends ExtensionMapperImpl public void addRequestedExtensionTables(SalesDocument salesDoc, JCoFunction func) super.addRequestedExtensionTables(salesDoc, func, null); addRequestedExtension(func, true, "ORDERADM_H", "ZZORDERADM_H6801", null); Additionally, you need to maintain the created mapper class in the factory-config.xml file, which is shown in the following figure: You must use code, such as the following, to announce that this new class or extension exists and needs to be considered by the system: <factoryClass name="com.sap.wec.app.esales.module.transaction.salesdocument.backend.interf.crm.mapper.Extensio nMapper" singleton="false" className="com.customer.wec.app.esales.module.salestransactions.backend.impl.crm.strategy.ExtMap perImpl" /> October 2013 121 Development and Extension Guide – Application-Specific Information 5.4 Shopping Cart - J2EE Data Persistence This extension example shows how you can extend the standard shopping cart and persist the additional data in the J2EE. In this example, we add an additional view to the shopping cart, where you can maintain additional URLs as links. These links will be persisted as shopping cart extensions in the J2EE database. They will be shown in the same view and it will be possible to navigate to the related URLs. 5.4.1 Creating Class Representing the Object to be Persisted (Serializable) Create a class that represents the object that needs to be persisted. In this example, we persist a URL and a description for the URL. The class needs to implement the interface Serializable, so that it can be serialized to the J2EE database, as shown in the following code: package com.customer.wec.app.esales.module.salestransactions.businessobject.impl; import com.customer.wec.app.esales.module.salestransactions.businessobject.interf.CustLink; public class CustLinkImpl implements CustLink { // CustLink inherits from Serializable private static final long serialVersionUID = 6448561614476397841L; protected String description; protected String url; @Override public String getDescription() { return description; } @Override public void setDescription(String description) { this.description = description; } @Override public String getUrl() { return url; } @Override public void setUrl(String url) { this.url = url; } } 122 October 2013 Development and Extension Guide – Application-Specific Information 5.4.2 Creating View Component Create a view component in the customer namespace that contains all required functionality (input fields, labels, buttons, and so on). In this example, this view component is named extcartlinks.xhtml and is shown in the following figure: The view component retrieves SalesDocumentBean as an attribute to get a reference to the SalesDocument business object. This is required to access the extension maps and is shown in the following code: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:cc="http://java.sun.com/jsf/composite" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:sales="http://java.sun.com/jsf/composite/sap/salestransactions/components" xmlns:wcf="http://java.sun.com/jsf/composite/wec" xmlns:wec="http://java.sap.com/wec/wcf/html"> <head> <title>My Links</title> </head> <body> <cc:interface componentType="sap.wec.ViewComponent"> <cc:attribute name="salesDocumentBean" type="com.sap.wec.app.esales.module.transaction.ui.beans.interf.SalesDocumentBean" /> </cc:interface> <cc:implementation> <wec:panelBox collapsible="false" id="pBform" styleType="form"> October 2013 123 Development and Extension Guide – Application-Specific Information <wec:panelGrid columnClasses="fw-formlayout-2col1, fw-formlayout-2col2" columns="2" id="pGdFrmLnks" styleClass="fw-form-layout"> <wec:panelBox collapsible="false" id="pBLFrmLnks" styleType="partform"> <wec:comment value="title for left part form" /> <wec:panelGroup id="pGFrmTitLLnks" layout="block" styleClass="fw-form-title"> <wec:title id="titFrmTitLLnks" level="5"> <wec:outputText id="txtFrmTitLLnks" value="#{i18n['sapsalestransactions.ui.extensJCart.title']}" /> </wec:title> </wec:panelGroup> <wec:panelGrid columnClasses="fw-form-label,fw-form-field" columns="2" id="pGdL" styleClass="fw-form-elements"> <wec:outputLabel for="itNewLinkUrl" value="#{i18n['sapsalestransactions.ui.extensJCart.urlLabel']}"/> <wec:inputText id="itNewLinkUrl" value="#{cc.vch.newUrl}"/> </wec:panelGrid> </wec:panelBox> <wec:panelBox collapsible="false" id="pBRFrmLnks" styleType="partform"> <wec:comment value="title for left part form" /> <wec:panelGroup id="pGFrmTitRLnks" layout="block" styleClass="fw-form-title"> <wec:title id="titFrmTitRLnks" level="5"> <wec:outputText id="txtFrmTitRLnks" value="" /> </wec:title> </wec:panelGroup> <wec:panelGrid columnClasses="fw-form-label,fw-form-field, fw-form- field" columns="3" id="pGdRLnks" styleClass="fw-form-elements"> <wec:outputLabel for="itNewLinkDesc" value="#{i18n['sapsalestransactions.ui.extensJCart.descLabel']}"/> <wec:inputText id="itNewLinkDesc" value="#{cc.vch.newDesc}"/> <wec:commandButton id="cBtSaveNewLink" value="#{i18n['sapsalestransactions.ui.extensJCart.saveButton']}" action="#{cc.vch.saveLink}"/> </wec:panelGrid> </wec:panelBox> </wec:panelGrid> <wec:panelGrid 124 October 2013 Development and Extension Guide – Application-Specific Information columnClasses="fw-formlayout-1col" columns="2" id="pGdFrmLnkTab" styleClass="fw-form-layout"> <wec:panelBox collapsible="false" id="pBRFrmLnkTab" styleType="partform"> <wec:dataTable value="#{cc.vch.linkList}" var="link"> <wec:column id="colLinks"> <f:facet name="header"> <wec:outputText id="headerIdLink" value="#{i18n['sapsalestransactions.ui.extensJCart.colMyLinks']}" /> </f:facet> <wec:outputLink value="#{link.url}"> <wec:outputText value="#{link.description}" /> </wec:outputLink> </wec:column> </wec:dataTable> </wec:panelBox> </wec:panelGrid> </wec:panelBox> </cc:implementation> </body> </html> 5.4.3 Creating View Component Handler 1. Create a view component handler class, which is the controller of the view. In this example, the class is called CustCartLinksViewHandlerImpl and extends SalesDocumentBeanViewHandlerImpl. The SalesDocumentBeanViewHandlerImpl class already provides getter, setter, and intialization methods for SalesDocumentBean. This ensures a convenient handling of SalesDocumentBean in the view component and the view component handler. The getLinkList method retrieves the extension map from the business object and puts our example extension to the map, as shown in the following code: package com.customer.wec.app.esales.module.transaction.ui.viewhandler; import java.util.ArrayList; import java.util.List; import java.util.Map; October 2013 125 Development and Extension Guide – Application-Specific Information import com.customer.wec.app.esales.module.salestransactions.businessobject.impl.CustLinkImpl; import com.customer.wec.app.esales.module.salestransactions.businessobject.interf.CustLink; import com.sap.wec.app.esales.module.transaction.ui.viewhandler.SalesDocumentBeanViewHandlerImpl; import com.sap.wec.tc.core.businessobject.BusinessObjectException; public class CustCartLinksViewHandlerImpl extends SalesDocumentBeanViewHandlerImpl { private static final String EXT_CUSTOMER_LINK_LIST = "ZZ_CustomerLinkList"; protected String newUrl; protected String newDesc; @SuppressWarnings("unchecked") public List<CustLink> getLinkList() { List<CustLink> linkList = (List<CustLink>) getSalesDocumentBean().getBO() .getHeader() .getExtensionData( EXT_CUSTOMER_LINK_LIST); if (null == linkList) { linkList = new ArrayList<CustLink>(); Map<Object, Object> extensionMap = getSalesDocumentBean().getBO() .getHeader() .getExtensionMap(); extensionMap.put(EXT_CUSTOMER_LINK_LIST, linkList); } return linkList; } public String getNewUrl() { return newUrl; } public void setNewUrl(String newUrl) { this.newUrl = newUrl; } public String getNewDesc() { return newDesc; } public void setNewDesc(String newDesc) { this.newDesc = newDesc; } public void saveLink() throws BusinessObjectException { CustLink link = new CustLinkImpl(); link.setDescription(newDesc); link.setUrl(newUrl); getLinkList().add(link); triggerUpdate(); setNewUrl(""); setNewDesc(""); } } 2. The extension is not registered in the back end. Therefore, you must remove the extension from the extension map before transferring it to the back end. For example, you could enhance the 126 October 2013 Development and Extension Guide – Application-Specific Information SalesDocumentBeanViewHandlerImpl class and remove the extension in the checkout method, as shown in the following code: package com.sap.wec.app.esales.module.transaction.ui.viewhandler; import com.customer.wec.app.esales.module.transaction.ui.viewhandler.CustCartLinksViewHandlerImpl; public class CustSalesDocumentBeanViewHandlerImpl extends SalesDocumentBeanViewHandlerImpl { /** * Overwrites the super implementation.<br> * ToDo: Describe the difference to super implementation.<br> * * @return * @see com.sap.wec.app.esales.module.transaction.ui.viewhandler.SalesDocumentBeanViewHandlerImpl#checkout() */ @Override public String checkout() { getSalesDocumentBean().getBO().getHeader().getExtensionMap().remove( CustCartLinksViewHandlerImpl.EXT_CUSTOMER_LINK_LIST); return super.checkout(); } } October 2013 127 Development and Extension Guide – Application-Specific Information 5.4.4 Registering View Component Handler The newly created view component handler and the view component need to be registered in the ui-repository.xml file, which is shown in the following figure: The following code shows how you can register the view component handler and the view component: <?xml version="1.0" encoding="UTF-8" standalone="no"?> <UIRepository xmlns="http://www.sap.com/wec/wcf/viewcomposition/ui-repository" xmlns:wec="com.sap.wec.core.config" module="salestransactions"> .... <ViewComponent name="extcartlinks" componentHandlerClassName="com.customer.wec.app.esales.module.transaction.ui.viewhandler.CustCar tLinksViewHandlerImpl"/> .... </UIRepository> 128 October 2013 Development and Extension Guide – Application-Specific Information 5.4.5 Overwriting Surrounding Component and Including New Component Finally, include the surrounding component, as follows: Identify the surrounding view (in this example leanbasket.xhtml) Copy the surrounding view and paste into the customer namespace to overwrite the deliverd component The following figure shows the leanbasket.xhtml view in the structure: October 2013 129 Development and Extension Guide – Application-Specific Information Enhance the pasted component (in this example, by including a new UI feature), as shown in the following code: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:cc="http://java.sun.com/jsf/composite" xmlns:f="http://java.sun.com/jsf/core" xmlns:sales="http://java.sun.com/jsf/composite/sap/salestransactions/components" xmlns:wcf="http://java.sun.com/jsf/composite/wec" xmlns:wec="http://java.sap.com/wec/wcf/html"> <cc:interface componentType="sap.wec.ViewComponent"> </cc:interface> <cc:implementation> <c:if test="#{cc.vch.basketAuthority}"> <wec:form id="fB"> .... <sales:extcartlinks id="cCH" rendered="#{cc.vch.salesDocumentBean.visibility['ext.showJavaCartExt']}" salesDocumentBean="#{cc.vch.salesDocumentBean}" /> .... </wec:form> </c:if> </cc:implementation> </html> 130 October 2013 Development and Extension Guide – Application-Specific Information 5.5 IPC Pricing If your pricing procedure contains attributes which are not supported in the standard system (see the information about standard attributes for IPC pricing in the back ends), you can provide those attributes by influencing the creation of IPC items on the Java side. For example, consider the situation where the product catalog displays list prices (that is, no IPC pricing is done in the product catalog) and you want the Java Cart shopping cart to display dynamic prices (that is, perform IPC pricing). 5.5.1 Standard Attributes for IPC Pricing (SAP CRM) This example assumes that the product catalog shows list prices. If the product catalog uses IPC pricing, the product- related attributes are read from MDM. The following figure shows the IPC attributes that are supported in the standard version of the Java Cart shopping cart: Source Attribute BP TAX_DEPART_CTY BP TAX_DEPART_REG BP TAX_DEST_REG BP TAX_DEST_CTY BP TAX_DEST_CTY_ISO BP TAX_DEPT_TYPE_01 BP TAX_DEPT_GRP_01 BP TAX_GROUP_BP_01 BP TAX_DEP_CTY_ISO BP TAX_TYPE_BP_01 BP TAXJURCODE BP TAXJURCODE_FROM BP TTE_PARTNER_ID BP SOLD_TO_PARTY BP KUNNR BP VBPA_AG-KUNNR BP VBPA_RG-KUNNR BP VBPA_WE-KUNNR BP VBPA_RE-KUNNR BP SHIP_COND BP KDGRP BP DIS_CHANNEL BP INCOTERMS1 BP VBAK-VKORG BP VBAK-KUNNR BP PMNTTRMS Item TAX_GROUP_P October 2013 131 Development and Extension Guide – Application-Specific Information Item TAX_TYPE_01 Item PRC_GROUP2 Item PRC_GROUP1 Item PRODH1 Item PRODH2 Item PRODH3 5.5.2 Standard Attributes for IPC Pricing (SAP ERP) In case the product catalog in the Java Cart scenario uses IPC pricing, the product-related attributes are read from MDM. The following table shows the supported attributes in case Java cart uses dynamic pricing whereas in the catalog, list prices are used. In addition, the supported attributes for the back-end cart are listed. Note When using the back-end cart, the prices in the cart and checkout are retrieved from SD. Only the prices for configurable products within the configuration UI are determined using the IPC, so it is only for these prices that the table shown below needs to be considered. Attribute Java Cart JCart Source BE Cart LAND1 yes BP no INCO1 yes BP yes INCO2 no n.a. yes KURST yes BP yes KUNNR yes BP yes KDGRP yes BP yes STCEG yes BP no PLTYP yes BP yes KONDA yes BP yes AWAHR yes BP no ZTERM yes BP yes TAXK1-9 yes BP no VKORG yes BP yes VTWEG yes BP yes VTWEG yes BP yes SPART yes BP yes VSBED no n.a. yes KONDM yes Item no PMATN yes Item yes PROVG yes Item no 132 October 2013 Development and Extension Guide – Application-Specific Information MVGR1-5 yes Item yes TAXM1-9 yes Item no SKTOF yes Item no BONUS yes Item no PRODH yes Item yes 5.5.3 Extension Example Extension Implementation The Java Cart shopping cart, whose logic is mainly implemented in class SalesDocumentDB, delegates the creation of IPC documents and items to a service class that communicates to IPC. If the Web shop runs against the SAP CRM back end, then the class is ServiceBasketIPCCRM. For the SAP ERP back end, the class is ServiceBasketIPCERP. The reason for having a separate class is mainly that the class SalesDocumentDB does not have a connection to the SAP CRM back end or the SAP ERP back end. Therefore, this service class is introduced, which can connect to the ABAP back end (maintained in the backendobjectconfig.xml file). Note that this class does not correspond to any business object. If a custom attribute should be maintained, this class must be extended, and a customer exit methodcustomerExitCreateIPCItems needs to be implemented, such as the following code (the example extends the class ServiceBasketIPCCRM): public class CustServiceBasketIPCCRM extends ServiceBasketIPCCRM { @Override public void customerExitCreateIPCItems(IPCDocument ipcDocument, IPCItemProperties[] itemProperties){ for (int i = 0; i<itemProperties.length;i++){ Map<String, String> itemAttributes = itemProperties[i].getItemAttributes(); itemAttributes.put("TG_BP_GUID", "ABCDEF"); itemProperties[i].setItemAttributes(itemAttributes); } } } It is also possible to do calls to SAP CRM or SAP ERP, if required. The connection can be obtained with getDefaultJCoConnection(). If the creation of the entire IPC document shall be influenced, you can use the following method: public void customerExitCreateIPCDocument(SalesDocument salesDoc, IPCDocumentProperties docProperties, HashMap<String, String> headerPriceAttributes, HashMap<String, String> headerIPCProps, boolean doPricing) Extension Registration As this example is concerned with the shopping cart, we need to create a new version of the salestransactions module in a new namespace. Suppose that the salestransactions module has been extended using the WCEM workbench. The module properties for the bo part could look like the following code: sap.com.moduleId=salestransactions sap.com.moduleNamespace=customer sap.com.extendsNamespace=sap sap.com.modulePart=bo October 2013 133 Development and Extension Guide – Application-Specific Information Next, we need to define the configuration file backendobject-config in the customer namespace, as the new service class is defined here. The respective excerpt from the metadata.xml file in the md part of the module looks as follows: … <config-file namespace="customer" part="bo" type="backend-objects">backendobject-config.xml </configfile> … Finally, we need to provide the new version of the backendobject-config.xml file, as shown in the following code: <?xml version="1.0" encoding="UTF-8"?> <backend xmlns="http://www.sap.com/wec/frw/tc/common/backendconfig" xmlns:wec="com.sap.wec.core.config" xmlns:xi="http://www.w3.org/2001/XInclude"> <businessObjects> <wec:ifValue variable="${backend}" value="crmdefault"> <businessObject name="ServiceBasketIPC" className= "com.customer.wec.app.esales.module.transaction.backend.basketdb.CustServiceBasketIPCCRM"/> </wec:ifValue> </businessObjects> </backend> Note that only the delta to the standard version is necessary. This file needs to be placed in the <namespace>.salestransactions.bo folder. Extension Activation After the extension code has been deployed, you need to activate it in Web Channel Builder. Create a new configuration and change the default namespace for the salestransactions module to customer. The following figure shows that the salestransactions module has been changed to the customer default namespace: In the salestransactions module of Web Channel Builder, make sure that you choose the extended UI for the shopping cart UI and enable price analysis just for the development phase. 134 October 2013 Development and Extension Guide – Application-Specific Information Note In the standard UI, the links for viewing the price analysis are not available. October 2013 135 Development and Extension Guide – Application-Specific Information 5.6 Order Search (SAP ERP) You can add or remove search fields and search result columns for orders in the SAP ERP back end. 5.6.1 New Search Criteria No view must be adapted to make additional search criteria available on the Web shop UI. You only need to change the generic search configuration file where the search criteria and the structure of the search result list are defined. The following figure shows the search in the standard system: The following figure shows the extended search criteria and includes an entry for Purchase order number: The file containing the generic search description is defined in the bo part of the salestransactions extension module. The use of the generic search configuration file for the salestransactions module is declared in the md part of the module in the metadata.xml file. Only the field to be added to the existing search criteria must be declared. If you want to remove fields from the delivered search criteria, all the necessary fields must be declared as part of a new description using a different name as shown in the following code: <description name="SearchCriteria_B2B_Order"resultlistDescription="Resultlist_B2B_SalesOrderERPCust"> <property name="ZZ_BSTKD_E" type="input"label="sapsalestransactions.ui.purchase.number"option="EQ" /> </description> 136 October 2013 Development and Extension Guide – Application-Specific Information 5.6.2 Search Results for New Search Criteria The changes described previously ensure that the search criterion is shown on the UI. However, you must write a new implementation for the BAdI ERP_ISA_GEN_DOC_SEL and activate it for the document type filter WEC_ORDER. You must copy the content of all the methods offered in the CL_IM_ERP_ISA_SFRW_ORD_SEL class to the new class. The PERFORM_SELECTION method is changed so that the new search criterion ZZ_BSTKD_E is handed over to the SAP ERP search framework. The following code shows an append structure added to the search criteria structure TDS_SW_SELCRIT_ORDER, which contains the field ZZ_BSTKD_E: LOOP AT gt_sel_opt INTO ls_sel_opt. CASE: ls_sel_opt-select_param. .... WHEN 'ZZ_BSTKD_E'. ls_selcrit-zz_bstkd_e = ls_sel_opt-low .... ENDCASE. ENDLOOP. Now, the SAP ERP search framework receives the search criterion that the user entered on the Web shop UI, but the system still cannot fetch the results from the SAP ERP database tables. A new document search class is necessary to achieve this. Any document search class implements the interface IF_FIND_SDOCS_BY_ELEMENTS. By implementing IF_FIND_SDOCS_BY_ELEMENTS~GET_INSTANCE, you associate the search criterion ZZ_BSTKD_E with the document search instance as shown in the following code: method if_find_sdocs_by_elements~get_instance. data: lt_inst type if_find_sdocs_by_elements=>tct_find_docs_by_instance, lv_bstkd_e type bstkd_e, ls_inst type if_find_sdocs_by_elements=>tcs_find_docs_by_instance. * Init exporting parameter clear et_find_by_inst. * Check if my instance actually is needed (in this case if at least Customer number is supplied) io_sw_sdoc->get_selcrit( exporting iv_selcrit_comp = 'ZZ_BSTKD_E' importing ev_selcrit_value = lv_bstkd_e ). if not lv_bstkd_e is initial. if not so_my_find_docs is bound. * Construct my get_docs singleton create object so_my_find_docs. endif. * Implementation for get_by_kunag available ls_inst-key = 'ZZ_BSTKD_E'. ls_inst-object_type = cl_lord_co=>sc_ot_head. ls_inst-seltype = if_find_sdocs_by_elements=>c_get_selection. ls_inst-inst = so_my_find_docs. append ls_inst to lt_inst. else. * Nothing to do as instance is not required return. endif. * Set exporting parameter October 2013 137 Development and Extension Guide – Application-Specific Information append lines of lt_inst to et_find_by_inst. endmethod. The selection of the results from VBKD is implemented in the method IF_FIND_SDOCS_BY_ELEMENTS~GET_DOCS_BY. The most important excerpt of coding from the method in the code above is shown in the following code: lt_vbeln = io_sw_sdoc->get_table_vbeln( ). io_sw_sdoc->get_selcrit( exporting iv_selcrit_comp = 'ZZ_BSTKD_E' importing ev_selcrit_value = lv_bstkd_e ). if lt_vbeln is initial. try. select vbeln from vbkd into corresponding fields of table lt_vbeln where bstkd_e eq lv_bstkd_e order by vbeln. catch cx_sy_dynamic_osql_error. raise exception type cx_sy_dynamic_osql_error. endtry. else. try. select vbeln from vbkd into corresponding fields of table lt_vbeln for all entries in lt_vbeln where vbeln eq lt_vbeln-vbeln and bstkd_e eq lv_bstkd_e. sort lt_vbeln by vbeln. catch cx_sy_dynamic_osql_error. raise exception type cx_sy_dynamic_osql_error. endtry. endif. The order in which these document selector instances run is important for system performance. When entering ZZ_BSTKD_E as search criteria, make sure that the document search instance class corresponding to it runs. The sold-to party field KUNAG is always an additional search criterion because Web shop customers must find only documents created by themselves. Therefore, in this case, two document search instances run. To determine the order of running, implement the BAdI BADI_SW_SELECTION_SEQ. For more information, see the following code: method IF_BADI_SW_SELECTION_SEQ~SET_SEL_SEQ. FIELD-SYMBOLS <ls_find_docs_by_instance> TYPE if_find_sdocs_by_elements=>tcs_find_docs_by_instance. LOOP AT it_find_docs_by_inst ASSIGNING <ls_find_docs_by_instance> WHERE ( key = 'ZZ_BSTKD_E ' ) AND object_type = cl_lord_co=>sc_ot_head AND seltype = if_find_sdocs_by_elements=>c_get_selection. READ TABLE ct_get_docs_inst WITH KEY inst = <ls_find_docs_by_instance>-inst TRANSPORTING NO FIELDS. IF sy-subrc NE 0. INSERT <ls_find_docs_by_instance> INTO TABLE ct_get_docs_inst. ENDIF. 138 October 2013 Development and Extension Guide – Application-Specific Information ENDLOOP. endmethod. 5.6.3 Adding New Fields to the Result List If you want to change the structure of the result list by adding a new column, add the new property to the result list. The following code shows the result list: <description name="Resultlist_B2B_SalesOrderERP"> <property name="WEC_SHIP_STATUS" type="text" columnTitle="sapsalestransactions.erp.ui.searching.criteria.label.shippingstatus" fieldOutputHandlerClass="com.sap.wec.app.esales.module.transaction.ui.util.GenericSearchDynamicC ontentOrderERP" fieldOutputHandlerMethod="getModifiedOverallStatus" /> </description> The following figure shows the purchase order number search criterion and the purchase order number column on the Web shop UI: If you want to remove an attribute from the result list, redefine the result list completely, and link it to the description of the search criteria using the attribute resultlistDescription, proceed as shown in the following code: <description name="SearchCriteria_B2B_Order"resultlistDescription="Resultlist_B2B_SalesOrderERPCust"> <property name="ZZ_BSTKD_E" type="input" label="sapsalestransactions.ui.purchase.number" option="EQ" /> </description> <description name="Resultlist_B2B_SalesOrderERPCust"> October 2013 139 Development and Extension Guide – Application-Specific Information <property name="VBELN" type="text" parameterType="rowkey" columnTitle="sapsalestransactions.erp.ui.searching.criteria.label.orderid" navigationTarget="#com.sap.wec.app.esales.module.transaction.ui.util.GenericSearchDynamicContent OrderERP$buildNavigationTargetOrder" /> <property name="ZZ_BSTKD_E" readOnly="true" columnTitle="sapsalestransactions.ui.purchase.number" /> <property name="WEC_SHIP_STATUS" type="text" columnTitle="sapsalestransactions.erp.ui.searching.criteria.label.shippingstatus"/> </description> In the SAP ERP back end, you must implement a mapping in the method GET_MAPPRING_TABLE of the implementation class for the BADI definition ERP_ISA_GEN_DOC_SEL as shown in the following code: ls_map_fields-object_type = 'HEAD'. ls_map_fields-field_external = 'ZZ_BSTKD_E'. ls_map_fields-field_internal = 'BSTKD_E'. ls_map_fields-assign = space. ls_map_fields-object_source = 'VBKD'. READ TABLE gt_sel_fields WITH KEY fieldname = ls_map_fields-field_external TRANSPORTING NO FIELDS. IF sy-subrc EQ 0. INSERT ls_map_fields INTO TABLE lt_map_fields. ENDIF. 140 October 2013 Development and Extension Guide – Application-Specific Information 5.6.4 Using the New Definition of the Search Description Save the configuration file for the search (that is, the generic-searchbackend-config.xml file) in the bo part of the salestransactions extension module as shown in the following figure: Note You must register this configuration file in the md part of the salestransactions extension module inside the metadata.xml file. This file is shown in the previous figure. October 2013 141 Development and Extension Guide – Application-Specific Information 5.7 Display of Schedule Lines (SAP ERP) This example explains how you can enable the display of schedule lines for orders. In the standard delivery, this is not supported for WCEM deployed against SAP ERP. You need to extend the salestransactions module in your namespace. 1. Register factory-config.xml for extensions. For the schedule lines to be read, you need to do extensions in the bo part of the salestransactions module. This extension is activated through a configuration file called factory-config.xml, therefore you need to state that this configuration file needs to be extended. This is done in metadata.xml of your extension module, and activation looks like this: <config-file namespace="customer" part="bo" type="factory-config">factory- config.xml</config-file> 2. Create a new implementation class for reading the schedule lines from SAP ERP and activate it. SAP ERP has to read the schedule line information along with the sales document items. Therefore you need to extend the so-called item request parameters for the SAP ERP call. This needs to be done in an extension to the central class that takes care of reading a sales document, namely GetAllStrategyERP in com.sap.wec.app.esales.module.transaction.salesdocument.backend.impl.erp.strategy. The implementation might look like this: public class CustGetAllStrategyERP extends GetAllStrategyERP605 { protected void buildDefaultItemObjectRequestParameters( JCoFunction function, boolean isDocFlowRead, BackendState baseDocErp) { super.buildDefaultItemObjectRequestParameters(function, isDocFlowRead, baseDocErp); JCoTable objReq = function.getImportParameterList().getTable( "IT_ITEM_OBJREQ"); objReq.appendRow(); objReq.setValue("OBJECT", "SLINE"); objReq.setValue("COMV_REQUEST", "X"); objReq.setValue("COMR_REQUEST", "X"); objReq.setValue("DEF_REQUEST", ""); } } This class is being instantiated by a factory that takes care of the classes for exchanging data with SAP ERP SD via LO-API: public class CustStrategyFactory extends StrategyFactoryERP { @Override public GetAllStrategy createGetAllStrategy() { return new CustGetAllStrategyERP(); } } 142 October 2013 Development and Extension Guide – Application-Specific Information 3. Register this factory in the above mentionend factory-config.xml <your namespace>/salestransactions/bo/factory-config.xml. <factoryClass name="STStrategyFactoryERP" singleton="false" className="com.customer.wec.app.esales.module.transaction.salesdocument.backend.impl.erp.s trategy.CustStrategyFactory" /> October 2013 143 Development and Extension Guide – Application-Specific Information 5.8 Reading of Additional Attributes (SAP CRM) You can enhance the Java back-end layer for the SAP CRM back end to enable the system to read and update attributes that are already part of the Web Channel function module interfaces (CRM_WEC_ORDER_SET and CRM_WEC_ORDER_GET), but not part of the delivered Java back-end layer. For example, you can enhance the Java back-end layer to write and read business partners with a specific partner function (in this case, vendor) on item level. The following example code contains some calls to helper methods that already exist in delivered coding (for example, addPartnerFieldParameter). Depending on the required extension, similar helper methods must be written as an extension as well. 1. Inform the back end which fields will be updated. To write fields to the SAP CRM back end layer, you must inform the back end which fields you want to update. You do this by filling a table of CRM_WEC_ORDER_SET interface with naming convention *SET, in this example, IT_FIELDS_PARTNER_SET. In this example, you create an extension of the PartnerMapperImpl class (for example, ExtensionPartnerMapperImpl) and overwrite the method addUpdatedPartnerFields as shown in the following code: /** * Which field shall be updated */ @Override public void addUpdatedPartnerFields(SalesDocument salesDoc, JCoFunction func, ControlParams controlParams) throws BackendMappingException { super.addUpdatedPartnerFields(salesDoc, func, controlParams); String partnerFunction; JCoTable partnerFields = func.getTableParameterList().getTable( RFCConstantsCRM.InputTable.PARTNER_FIELDS_SET); String guid = null; String handle = null; partnerFunction = partnerFctMapping.getPartnerFunctionCRM(PartnerFunctionData.VENDOR); ItemList items = salesDoc.getItemList(); int numOfItems = items.size(); for (int index = 0; index < numOfItems; index++) { Item item = items.get(index); TechKey techKey = item.getTechKey(); // for new items, use handle, techkey in other case if (TechKey.isEmpty(techKey)) { guid = ""; handle = String.valueOf(item.getHandle()); } // existing item else { guid = techKey.getIdAsString(); 144 October 2013 Development and Extension Guide – Application-Specific Information handle = ""; } addPartnerFieldParameter(partnerFields, guid, handle, RFCConstantsCRM.Kind.ADMIN_ITEM, partnerFunction, PARTNER_ID); } } 2. Write the field values from the business object into the JCO structure. Find out which structure in the back end expects the field values to be taken over. In this example, the partners are written into table IT_PARTNER. Therefore, the required extension of method writePartners in PartnerMapperImpl would appear as shown in the following code: @Override public void writePartners(SalesDocument salesDoc, JCoFunction func, ControlParams controlParams) throws BackendMappingException { super.writePartners(salesDoc, func, controlParams); JCoParameterList tableParams = func.getTableParameterList(); JCoTable partnerTable = tableParams.getTable(PARTNER_TABLE_SET); JCoTable partnerFields = tableParams.getTable(RFCConstantsCRM.InputTable.PARTNER_FIELDS_SET); TechKey techKey = salesDoc.getTechKey(); String scenario = salesDoc.getTransactionConfiguration().getScenario(); ItemList itemList = salesDoc.getItemList(); int numOfItems = itemList.size(); String itemKind = RFCConstantsCRM.Kind.ADMIN_ITEM; String itemGUID; String itemHandle; for (int index = 0; index < numOfItems; index++) { Item item = itemList.get(index); PartnerList partnerList = item.getPartnerListData(); techKey = item.getTechKey(); if (TechKey.isEmpty(techKey)) { itemGUID = ""; itemHandle = item.getHandle(); } else { itemGUID = techKey.getIdAsString(); itemHandle = ""; } October 2013 145 Development and Extension Guide – Application-Specific Information Map<String, String> bpRolesAndAndPartnerFunctions = getItemBPRolesAndPartnerFunctions( salesDoc, item); // Add customer specific business partner function (e.g. Vendor) String bpRoleVendor = PartnerFunctionData.VENDOR; bpRolesAndAndPartnerFunctions.put(bpRoleVendor, partnerFctMapping.getPartnerFunctionCRM(bpRoleVendor)); // End customer specific business partner function (e.g. Vendor) for (Entry<String, String> entry : bpRolesAndAndPartnerFunctions.entrySet()) { String bpRole = entry.getKey(); String partnerFunction = entry.getValue(); Address address = searchItemPartnerAddress(item, bpRole); writePartner(itemGUID, itemHandle, itemKind, bpRole, partnerFunction, partnerList, partnerTable, address, partnerFields, null, scenario, null); } } } 3. Request additional fields to be read from the back end. When performing the read from the ABAP back end, the back end needs to know which data shall be read, for performance reasons. The following code shows how, in this example, you would request the vendor to be read from the back end: @Override public void addRequestedPartnerFunctions(SalesDocument salesDoc, JCoFunction func, ControlParams controlParams) throws BackendMappingException { super.addRequestedPartnerFunctions(salesDoc, func, controlParams); JCoTable parameters = func.getTableParameterList().getTable( RFCConstantsCRM.InputTable.PARAMETERS); parameters.appendRow(); parameters.setValue(RFCConstantsCRM.Name.PARAMETER, PARTNER_TABLE_GET); String partnerFunction; JCoTable partners = func.getTableParameterList().getTable( RFCConstantsCRM.InputTable.PARTNER_REQUESTED); // only one line without guid means -> get all items // VENDORS partnerFunction = partnerFctMapping.getPartnerFunctionCRM(PartnerFunctionData.VENDOR); partners.appendRow(); // empty guid means - get this for all items partners.setValue(REF_KIND, RFCConstantsCRM.Kind.ADMIN_ITEM); partners.setValue(PARTNER_FCT, partnerFunction); 146 October 2013 Development and Extension Guide – Application-Specific Information } The coding enhances the method addRequestedPartnerFunctions in class PartnerMapperImpl. 4. Read fields values from JCO structure into the business object. In this example, all requested partners are filled by the delivered code into the PartnerList on item level. Therefore, no extension is required. In general, one would again enhance the required mapper class and read method. The read methods have the JCO structure and the business object as a parameter. Therefore, you would read the required data from the JCO structure and pass it to the business object as shown in the following code: @Override protected void readMethod(JCoTable table, SalesDocument salesDoc, ControlParams controlParams) throws BackendMappingException { int numLines = table.getNumRows(); for (int index = 0; index < numLines; index++) { table.setRow(index); // Read data from JCO Structure String kind = table.getString(REF_KIND); String partnerFct = table.getString(PARTNER_FCT); String partnerId = table.getString(PARTNER_ID); TechKey techKey = new TechKey(table.getString(PARTNER_GUID)); ... // Pass above data to intended business object } } October 2013 147 Development and Extension Guide – Application-Specific Information 5.9 Delivery Types and Requested Delivery Dates You can create a link between delivery type and requested delivery date (this example enhancement focuses on the UI and BO layer in the salestransactions module). When the delivery type is changed, the requested delivery date is adapted (and also the other way around). You can enhance the following: The order business object to check the delivery type and set the requested delivery date accordingly The shopping cart UI so that whenever the requested delivery date is changed, the delivery type is changed as well (if needed) 5.9.1 Adapting BO Layer to Set Requested Delivery Date 1. To enhance the order BO, make an entry in the businessobject-config.xml file to use the enhanced order object instead of the standard one, as shown in the following code: <businessObject name="Order" className="com.customer.wec.app.esales.module.salestransactions.businessobject.impl.CustOr derImpl" /> 2. To check the delivery type and set the requested delivery date accordingly, adapt the newly generated object CustOrderImpl, as shown in the following code: @Override public void update() throws CommunicationException { adaptRequestedDeliveryDate(); super.update(); } private void adaptRequestedDeliveryDate() { Header orderHeader = getHeader(); String shipCond = orderHeader.getShipCond(); Date currentDate = orderHeader.getReqDeliveryDate(); Date expressDate = getExpressDeliveryDate(); Date standardDate = getEarliestStandardDeliveryDate(); // overnight means as fast as possible if (OVERNIGHT_SHIPPING.equals(shipCond) && currentDate.after(expressDate)) { applyReqDelDate(expressDate); } // standard means not before standard delivery time if (STANDARD_SHIPPING.equals(shipCond) && currentDate.before(standardDate)) { applyReqDelDate(standardDate); } } private void applyReqDelDate(Date reqDeliveryDate) { applyReqDelDateToHeader(reqDeliveryDate); applyReqDelDateToItems(reqDeliveryDate); } ... 148 October 2013 Development and Extension Guide – Application-Specific Information 5.9.2 Adapting UI Layer to Set Delivery Type Depending on Requested Delivery Date To enhance the system so that it reacts to any change of the requested delivery date by changing the delivery type accordingly, you must enhance the HeaderViewHandler of the extended UI as follows: 1. Add the enhanced class to the ui-repository.xml file, as shown in the following code: <ViewComponent name="richbasketheader" componentHandlerClassName= "com.customer.wec.app.esales.module.transaction.ui.viewhandler.CustSalesDocumentHeaderView HandlerImpl"/> 2. So that the enhanced view handler overrides the method called by the value change listener of the requested delivery date and executes the specific changes, use code similar to the following: @Override public boolean reqDeliveryDateUpdateRequired() { boolean updateRequired = super.reqDeliveryDateUpdateRequired(); // change shipping condition depending on requested delivery date, if // necessary Date expressDate = getExpressDeliveryDate(); Header headerBO = getSalesDocumentHeaderBean().getBO(); Date reqDeliveryDate = headerBO.getReqDeliveryDate(); String shipCond = headerBO.getShipCond(); if (reqDeliveryDate.after(expressDate) && shipCond.equals(CustOrderImpl.OVERNIGHT_SHIPPING)) { headerBO.setShipCond(CustOrderImpl.STANDARD_SHIPPING); updateRequired = true; } if (!reqDeliveryDate.after(expressDate) && !shipCond.equals(CustOrderImpl.OVERNIGHT_SHIPPING)) { headerBO.setShipCond(CustOrderImpl.OVERNIGHT_SHIPPING); updateRequired = true; } return updateRequired; } 3. The requested delivery date is AJAX enabled and the system only refreshes those parts of the UI that could have changed. In the standard system, the delivery type could never change by changing the requested delivery date. Therefore, to achieve a re-rendering, the ID of the delivery type component on the UI must be added to the list of IDs to be re-rendered. You can do this by overwriting the method with code such as the following: @Override public String getReRenderIds() { String reRenderIds = super.getReRenderIds(); TransactionConfiguration transactionConfiguration = getModuleAccess().getTransactionConfiguration(); // in case of java basket + list pricing, delivery type is not // displayed, hence adding it to the re-render IDs would cause a dump October 2013 149 Development and Extension Guide – Application-Specific Information if (!isJavaBasket() || transactionConfiguration.isForceIPCPricing()) { reRenderIds += SalesTransactionsUtil.RERENDER_SEPARATOR + ID_OT_DELIVER_TYPE; } return reRenderIds; } 150 October 2013 Development and Extension Guide – Application-Specific Information 5.10 Proposed Shopping Templates A typical extension of the shopping templates could be to enable assigning a shopping template to other Web shop customers as a proposed shopping template on the UI. A Web shop administrator (for example, a sales representative) could propose shopping templates to users. For Web shop customers, those proposed shopping templates have the same meaning as product recommendations. You can assign Web shop customers (sold-to parties) to proposed shopping templates for various validity periods. Web shop customers that are assigned to a proposed shopping template see it in their list of shopping templates. Proposed shopping templates are read-only for Web shop customers. However, they can use proposed shopping templates to order products. They can also copy proposed shopping templates and change them. A Web shop administrator requires authorization to assign Web shop customers to proposed shopping templates. In the BO layer of the shoppingtemplates module, SAP delivers public methods that enable Web shop administrators to do the following: Create shopping templates for other users Assign sold-to parties to shopping templates Change the validity period for a shopping template Change the owner for a shopping template Details about the shopping templates business objects can be found in the javadoc documentation of the shopping templates module’s interface part. Furthermore, SAP delivers an authorization concept to ensure that only users with a special authorization can perform these actions. To assign an authorization to a Web shop administrator, go to role maintenance (transaction PFCG) and enhance a role, in SAP CRM back end for the authorization object WEC_AUTH and in SAP ERP back end for the authorization object WEC_AUTERP (Web Channel Document Authorizations). You do this by choosing Change -> Authorizations -> Change Authorization Data. Expand the tree and choose Change Object Types for Authorization and enter SHTEMPLEXTMAINT (Shopping Templates Extended Maintenance). For more information about the authorization concept, see the Security Guide for SAP Web Channel Experience Management on SAP Service Marketplace at http://service.sap.com/wec-inst. You can also see SAP Library for SAP Web Channel Experience Management on SAP Help Portal at http://help.sap.com/wec. Choose a release and then Application Help. In SAP Library, choose SAP Web Channel Experience Management -> User Management -> Authorization Concept. The following example shows how to enhance the existing UI so that Web shop users with special authorization can use the Web shop to create a shopping template with themselves as the owner and to assign sold-to parties to the shopping template. Furthermore, the validity period of the shopping template (which is not shown on the UI) is changed in this example, so that the proposed shopping template is only visible for a certain period to the assigned Web shop customers. October 2013 151 Development and Extension Guide – Application-Specific Information 1. Create an extension module for the shopping template module, including corresponding applications and Web Channel Builder configuration. In this example, it is sufficient to create an md and ui part (Development Component (DC)). For more information about Web Channel Builder, see the section on Web Channel Builder modules in this guide. You can also see SAP Library for SAP Web Channel Experience Management on SAP Help Portal at http://help.sap.com/wec. Choose a release and then Application Help. In SAP Library, choose SAP Web Channel Experience Management -> Configuration -> Configuring Web Channel Applications (Web Channel Builder). The new DCs might look like this: 152 October 2013 Development and Extension Guide – Application-Specific Information 2. Add the following additional dependencies to the new ui DC: 3. Add the following additional dependencies to the new dpu DC: 4. Add the following content to the metadata.xml file of the created md part. This enables you to use an extended view handler class for your new ui view: metadata.xml <?xml version="1.0" encoding="UTF-8"?> <module xmlns="http://www.sap.com/wec/frw/tc/modules/metadata" lazyLoad="true" mainModule="false" moduleID="shoppingtemplates"> <moduleType>application</moduleType> <configForModule>shoppingtemplates</configForModule> <config-file namespace="customer" part="ui" type="ui-repository">ui- repository.xml</config-file> </module> October 2013 153 Development and Extension Guide – Application-Specific Information 5. Specify your own namespace (here customer) in the module.properties file of both the md part and ui part. This could look like this: module.properties sap.com.moduleId=shoppingtemplates sap.com.moduleNamespace=customer sap.com.extendsNamespace=sap sap.com.modulePart=ui 6. Copy the file shopping-template.xhtml from the original shopping template ui DC to your extension ui DC. 7. Enhance the view by adding a new button called Add Assignees: shopping-template.xhtml <c:if test="#{cc.vch.listFilled}"> <wec:panelBox collapsible="false" id="pBTTB" styleType="top-table-toolbar"> <wec:panelGroup id="pgRG" styleClass="fw-table-toolbar-btn" layout="block"> <wec:commandButton id="cBATB" styleType="form-em" tabindex="20" value="#{i18n['shoppingtemplates.ui.AllToCart']}"> <wec:ajax event="click" id="ajATB" execute="@form" listener="#{cc.vch.addAllItemsToBasket}" render="msgContentHdr pGItm pGpMini" /> </wec:commandButton> <c:if test="#{!cc.vch.readOnlyTemplate}"> <wec:commandButton id="cBSaQu" tabindex="20" value="#{i18n['shoppingtemplates.ui.saveQuantities']}"> <wec:ajax event="click" id="ajSQ" execute="@form" listener="#{cc.vch.saveQuantities}" render="msgContentHdr pGItm" /> </wec:commandButton> 154 October 2013 Development and Extension Guide – Application-Specific Information <!-- New button --> <wec:commandButton id="cBSaQu2" tabindex="20" value="Add Assignees" rendered="#{cc.vch.assignmentButtonVisible}"> <wec:ajax event="click" id="ajSQ2" execute="@form" listener="#{cc.vch.addAssignees}" render="msgContentHdr pGItm" /> </wec:commandButton> <!-- End of new button --> </c:if> </wec:panelGroup> </wec:panelBox> 8. Create a custom view handler in your ui DC to manage the newly created view. ShoppingTemplateViewhandlerImplExt.java package customer.beans.impl; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashSet; import java.util.Set; import javax.faces.event.AjaxBehaviorEvent; import com.sap.wec.app.esales.module.shoppingtemplates.beans.impl.ShoppingTemplateViewhandlerImpl ; import com.sap.wec.app.esales.module.shoppingtemplates.businessobject.interf.ShoppingTemplatePerm issionControl; October 2013 155 Development and Extension Guide – Application-Specific Information import com.sap.wec.app.esales.module.shoppingtemplates.businessobject.interf.ShoppingTemplatePerm issionControl.Action; import com.sap.wec.app.esales.module.shoppingtemplates.businessobject.intl.interf.ShoppingTemplat eInternal; import com.sap.wec.tc.core.businessobject.BusinessObjectException; public class ShoppingTemplateViewhandlerImplExt extends ShoppingTemplateViewhandlerImpl { public void addAssignees(AjaxBehaviorEvent notUsed) throws BusinessObjectException { Set<String> soldTos = retrieveAssigneesFromSomeWhere(); this.shoppingTemplate.setAssignedSoldTos(soldTos); setValidityperiod(); this.shoppingTemplate.update(); } // In this example, we have hard-coded the GUIDs of the sold-to-parties, which should be assigned. // Of course the customer might want to read the sold-tos from the CRM backend. In this case this method // would be in the bo-part private Set<String> retrieveAssigneesFromSomeWhere() { Set<String> soldTos = new HashSet<String>(); soldTos.add("9E3C4D4FB4C61062E10000000A428783"); soldTos.add("1804E24F1229004CE10000000A4282C0"); soldTos.add("8906E24F1229004CE10000000A4282C0"); return soldTos; } private void setValidityperiod() { Calendar cal = new GregorianCalendar(2013, 06, 30); this.shoppingTemplate.setValidFrom(new Date()); this.shoppingTemplate.setValidTo(cal.getTime()); } public boolean isAssignmentButtonVisible() throws BusinessObjectException { ShoppingTemplateInternal shoppingTemplate = (ShoppingTemplateInternal) this.shoppingTemplate; ShoppingTemplatePermissionControl permissionControl = shoppingTemplate .getPermissionControl(); return !this.shoppingTemplate.isReadOnlyTemplate() && permissionControl.hasPermission( Action.CHANGE_OWN_TEMPLATE_ASSIGNMENTS, shoppingTemplate); } } 156 October 2013 Development and Extension Guide – Application-Specific Information 9. Add a ui-repository.xml file in your ui DC with the following content: ui-repository.xml <?xml version="1.0" encoding="UTF-8" standalone="no"?> <UIRepository xmlns="http://www.sap.com/wec/frw/tc/ui/runtime/ui-repository" xmlns:wec="com.sap.wec.core.config" module="shoppingtemplates"> <ViewComponent name="shopping-template" componentHandlerClassName="customer.beans.impl.ShoppingTemplateViewhandlerImplExt" /> </UIRepository> 10. Add the source root folder for your chosen namespace (in this example customer) to the assembly public part of the ui DC, as a Java package tree. Otherwise, the new class added might not be deployed on the server and an exception might occur since the class is not found. 11. Make sure you have the correct configuration within Web Channel Builder. October 2013 157 Development and Extension Guide – Application-Specific Information Proposed shopping templates are read-only for the assigned Web shop customers. Web shop customers can use proposed shopping templates to order products and they can copy and change copied proposed shopping templates. This is represented by a lock icon next to the shopping template’s name. There is also an icon for the owner of the proposed shopping template, which visualizes that the shopping template has assignees and that all changes such as deleting or removing products are also visible to these assignees. 158 October 2013 Development and Extension Guide – Application-Specific Information 5.11 Document Converter Manager Document converter manager manages how a document should be converted to a certain format, or how a file in a certain format should be converted into a certain document. The document converter manager instantiates a convertible class. This class performs the conversion into the document or format. 5.11.1 Extending the Module Settings A convertible is part of the module setting. An extension of the module needs to be performed with the WCEM eclipse plug-in. Only the BO and UI parts are necessary. The plug-in also generates the DPU development component. The following figure shows the module settings, for example, the enhancement of the salestransactions module: October 2013 159 Development and Extension Guide – Application-Specific Information 160 October 2013 Development and Extension Guide – Application-Specific Information 5.11.2 Implementing and Registering a New Convertible Implement a convertible in the BO part of the extended module. There you have to implement a class that implements the interface Convertible. An example is shown in the figure below: The registration is performed by inserting an entry in the factory_config.xml file, with key (name UDM_ + sourceObject+ _ + targetObject), with which the document manager instantiates the class that performs the conversion of the business object. This figure shows an example: Note You can also set a converter util class to separate the business part and the technical part, which can be the same for different documents. This allows you to reuse the technical part in different modules. You only have to register the class (second line in the figure above). The naming convention is UDM_CONVERTER_UTIL_ + formatName. October 2013 161 Development and Extension Guide – Application-Specific Information 5.11.3 Implementing the UI Part You get the document manager by implementing the following lines: You get the convertible by implementing these lines: In the convertible, you can set the source object, trigger the conversion, and then get the target object. 162 October 2013 Development and Extension Guide – Application-Specific Information 5.12 Mapping of Back-End Messages to UI Messages You can influence which texts are shown on the Web Channel UI with messages that come from the SAP ERP or SAP CRM back end. For example, message 097 of message class SLS_LORD in SAP ERP reads: Sales order item &1 &2 has already been delivered (first argument is the document number, second argument is the ID of the item ordered). For the Web shop customer, a different message text would be more user-friendly, for example: Product (0) has been shipped. 1. Define the type rfc_messages in the metadata.xml in the md part of the enhanced salestransactions module as follows: <module xmlns="http://www.sap.com/wec/frw/tc/modules/metadata" lazyLoad="true" mainModule="false" moduleID="salestransactions"> <moduleType>application</moduleType> <configForModule>salestransactions</configForModule> ... <config-file namespace="customer" part="bo" type="rfc_messages">messages.xml</config-file> ... </module> 2. Create the file messages.xml in the bo part of the enhanced salestransactions module with the following content: <messages xmlns="http://www.sap.com/rfcmessages/" xmlns:wec="com.sap.wec.core.config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sap.com/rfcmessages/ messages.xsd "> <wec:ifValue variable="${backend}" value="erpdefault"> <message> <source id="SLS_LORD" number="097" type="E" /> <destination type="E" resource_key_shorttext=sapsalestransactions.erp.ui.rfc.messages.label.lord097 resource_key_longtext="" /> </message> </wec:ifValue> </messages> As the message above can be raised by the SAP ERP back end only, we made the message mapping valid only for shops running against SAP ERP (note the use of <wec:ifValue> above). The message mapping above can be put into words like: When the error message 097 defined in class SLS_LORD is raised by the back end, this message will be shown on the UI as an error message having the text maintained under the resource key sapsalestransactions.erp.ui.rfc.messages.label.lord097. You can access the message in the Java code by accessing an instance of the TransactionConfiguration, as follows: List<RfcMessage> lst= transConf.getRFCMessages().getMessages(); October 2013 163 Development and Extension Guide – Application-Specific Information 5.13 Additional Pricing in Cart or Order In order to trigger additional pricing in the cart or the order, you have to extend the salestransactions module. For this example, the bo and md parts are relevant. backendobject-config.xml (should be placed in the bo part of the extended module): <?xml version="1.0" encoding="UTF-8"?> <backend xmlns="http://www.sap.com/wec/frw/tc/common/backendconfig" xmlns:wec="com.sap.wec.core.config" xmlns:xi="http://www.w3.org/2001/XInclude"> <businessObjects> <wec:ifValue variable="${backend}" value="erpdefault"> <businessObject name="AdditionalPricing" type="AdditionalPricing" className="com.sap.wec.app.esales.module.transaction.salesdocument.backend.impl.erp.AdditionalPr icingImpl" attributes="standalone"> <params> <param name="basket.additionalCall" value="TRUE" /> </params> </businessObject> </wec:ifValue> </businessObjects> </backend> metadata.xml (should be placed in the md part of the extended module): <?xml version="1.0" encoding="UTF-8"?> <module xmlns="http://www.sap.com/wec/frw/tc/modules/metadata" lazyLoad="true" mainModule="false" moduleID="salestransactions"> <moduleType>application</moduleType> <configForModule>salestransactions</configForModule> ... <config-file namespace="customer" part="bo" type="backend-objects">backendobject- config.xml</config-file> ... </module> You can trigger additional pricing in the context of the order as well, for example if the ship-to party is changed in checkout via extension), and, in addition, also choose a different pricing type. See the possible pricing types in domain KNPRS in ABAP. To do so, the following parameters are available: <param name="order.additionalCall" value="FALSE" /> <param name="pricingType" value="H" /> 164 October 2013 Development and Extension Guide – Application-Specific Information 5.14In-Store Pickup If stores were originally created as ERP plants in SAP ERP (called sites in SAP Retail), you must have replicated business partners and ERP plants from SAP ERP to SAP CRM to use the in-store pickup function. Note that you must have replicated customer master data first. However, if you did not replicate customer master data first or you replicated ERP plants with no customer master data, you must extend SAP Web Channel Experience Management. This extension supports in-store pickup without the requirement that customers are associated with plants in SAP ERP. Background: The instore module creates sales items that have an in-store specific partner function. By default, this is the ISTP_partner function. Within this partner function, the business partner ID of the selected store is written. But this requires that in SAP ERP a customer is associated with the store (called plants in SAP ERP). The following extension modifies the behavior of the instore module so that the ID of the logged-on Web shop customer is written to the ISTP partner function and not the ID of the store: 1. Create an extension module for the instore module, including corresponding test applications and Web Channel Builder configuration. In this case, it suffices to create an md and bo part (Development Component (DC)). For more information about Web Channel Builder, see the section on Web Channel Builder modules in this guide. You can also see SAP Library for SAP CRM on SAP Help Portal at http://help.sap.com/wec. Choose a release and then Application Help. In SAP Library, choose SAP Web Channel Experience Management -> Configuration -> Configuring Web Channel Applications (Web Channel Builder). The new DCs might look as follows: 2. Add the following additional dependencies to the bo DC: wec/comm/mc/storelocator/intf wec/comm/mc/user/intf wec/comm/rc/transaction/intf wec/ecom/mc/salestransactions/intf wec/frw/tc/core wec/trade/mc/instore/bo wec/trade/mc/instore/intf Please be aware to have corresponding Enterprise Applications (one for the Application itself and another one for the configuration). These must have the following dependencies maintained: Web Channel Builder DC (called j2eeappwcb) with dependencies: October 2013 165 Development and Extension Guide – Application-Specific Information Application DC (called j2eeapp) with dependencies: 3. Add the following content to the metadata.xml file of the created md part. This enables you to use an extended module access class: <moduleClasses> <moduleAccessClass>com.sap.wec.app.trade.module.instore.modulemgmt.impl.InstoreModuleAccessIm plExt</moduleAccessClass> </moduleClasses> 4. Create class com.sap.wec.app.trade.module.instore.modulemgmt.impl.InstoreModuleAccessImplExt in the bo part using the following code: InstoreModuleAccessImplExt.java package com.sap.wec.app.trade.module.instore.modulemgmt.impl; import com.sap.wec.app.trade.module.instore.businessobject.InstoreShipToImplExt; import com.sap.wec.app.trade.module.instore.businessobject.intf.InstoreShipTo; public class InstoreModuleAccessImplExt extends InstoreModuleAccessImpl { @Override // we override this method in order to bring an extended implementation of // InstoreShipTo into play public InstoreShipTo createInstoreShipTo() { return new InstoreShipToImplExt(getBasketAccess(), getBusinessPartnerAccess().getAddressManager(), getBusinessPartnerAccess().getBusinessPartnerManager(), getAvailabilityCheckBO(), getInstoreConfiguration()); } } 166 October 2013 Development and Extension Guide – Application-Specific Information 5. Create class com.sap.wec.app.trade.module.instore.businessobject.InstoreShipToImplExt in the bo part using the following coding (this coding changes the partner ID of the in-store pickup partner function from store to user): InstoreShipToImplExt .java package com.sap.wec.app.trade.module.instore.businessobject; import com.sap.wec.app.common.mc.module.storelocator.businessobject.interf.StoreDetail; import com.sap.wec.app.common.module.businesspartner.businessobject.interf.AddressManager; import com.sap.wec.app.common.module.businesspartner.businessobject.interf.BusinessPartner; import com.sap.wec.app.common.module.businesspartner.businessobject.interf.BusinessPartnerManager; import com.sap.wec.app.common.module.transaction.item.businessobject.interf.Item; import com.sap.wec.app.common.module.transaction.order.businessobject.interf.PartnerListEntry; import com.sap.wec.app.esales.module.transaction.modulemgmt.interf.BasketAccess; import com.sap.wec.app.trade.module.instore.businessobject.impl.InstoreSalesItemHelperImpl; import com.sap.wec.app.trade.module.instore.businessobject.impl.InstoreShipToImpl; import com.sap.wec.app.trade.module.instore.businessobject.intf.AvailabilityCheckBO; import com.sap.wec.app.trade.module.instore.businessobject.intf.InstoreConfiguration; import com.sap.wec.app.trade.module.instore.businessobject.intf.InstoreSalesItemHelper; public class InstoreShipToImplExt extends InstoreShipToImpl { private final BusinessPartnerManager bpManager; private final InstoreConfiguration instoreConfiguration; // we have to override the constructor to store bpManager and // instoreConfiguration since they have been defined private in the // superclass public InstoreShipToImplExt(BasketAccess basketAccess, AddressManager addressManager, BusinessPartnerManager businessPartnerManager, AvailabilityCheckBO availabilityCheckBO, InstoreConfiguration instoreConfiguration) { super.setBasketAccess(basketAccess); super.setBpManager(businessPartnerManager); super.setAvailabilityCheckBO(availabilityCheckBO); super.setAddressManager(addressManager); super.setInstoreConfiguration(instoreConfiguration); this.bpManager = businessPartnerManager; this.instoreConfiguration = instoreConfiguration; } @Override // we need to override this method in order to change the partner Id of the // instore pickup partner function. Instead of the (default) store Id we // enter the ID of the logged in user. The method gets called in two cases: // 1. when the product is added to the basket and 2. when the user logs on // (triggerd by the SoldToChangedEvent). public void addShipTo(Item item, StoreDetail storeDetail) { super.addShipTo(item, storeDetail); BusinessPartner soldTo = bpManager.getSoldto(); October 2013 167 Development and Extension Guide – Application-Specific Information if (soldTo == null) { return; } InstoreSalesItemHelper helper = new InstoreSalesItemHelperImpl(); String partnerId = bpManager.getSoldto().getId(); if (helper.isInstoreItem(item, instoreConfiguration)) { PartnerListEntry entry = item.getPartnerListData().getPartnerData( instoreConfiguration.getPartnerFunctionInStorePickup()); entry.setPartnerId(partnerId); } } } 6. Add source root folder com as Java package tree to the assembly public part of the bo DC. Otherwise, the two classes added might not be deployed on the server and an exception might occur for the class not found. 7. Take care of having the correct configuration within WCEM: 168 October 2013 Development and Extension Guide – Application-Specific Information 6 Payment Process 6.1 Payment Service Providers You can enable your Web shop to accept payment from your Web shop customers by way of payment service providers (PSPs). Integrating payment service providers enables your Web shop to offer the payment methods provided by payment service providers to their customers. For more information, see SAP Library on SAP Help Portal at http://help.sap.com/wec. Choose a release and then Application Help. In SAP Library, choose SAP Web Channel Experience Management -> E-Commerce -> Checkout -> Payment Methods -> Payment Service Providers. If you want to integrate payment service providers, you must implement extensions. Two major decisions will influence the scope: Which payment service provider will you integrate? Each payment service provider offers a specific technical framework to integrate their services. If you use PayPal, you must start your integration as described in chapter Web Service Integration (PayPal Example). Note The examples are based on webservices provided by PayPal. If you integrate another payment service provider, you must adapt these examples to the technical services provided by the payment service provider. Which back end integration scenario will you use? October 2013 169 Development and Extension Guide – Application-Specific Information 6.1.1 Architecture Overview The following figure shows an overview of the system architecture: The payment service provider integration framework enables you to integrate with various PSP platforms. The current integration is based on the advanced payment concept. By submitting orders, Web shop customers trigger the initial communication to PSPs. Web shop customers are redirected to the PSP system to confirm payments. The Web shop receives confirmations containing unique transaction IDs and statuses of payments (for example, complete or pending). PSP payment statuses are used in order management to manage logistic execution and ensure that merchants receive payment in Financials. Note Note that the payment service provider interface (PSP IF) is a reuse component which is part of both the SAP CRM back end and the SAP ERP back end. 170 October 2013 Development and Extension Guide – Application-Specific Information 6.1.2 Web Service Integration (PayPal Example) SAP delivers a generic interface for the integration of payment service providers. This section describes relevant activities to consume Web services. We will use PayPal services as an example. The PayPal Web service is a third party product. More information regarding the PayPal API can be found in the PayPal Developer Area: https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/howto_api_overview The SAP system consumes the services provided by PayPal in order to trigger operations on the PayPal system such as triggering a payment or a refund. This PayPal integration sees the SAP system as a consumer. The SAP system sends a request to the PayPal system and the PayPal system sends back a response. However, PayPal does not directly call the SAP system. In other words, the integration follows a ‘pull’ approach but there is no ‘push’. For more information about using PayPal as a payment service provider, see http://www.paypal.de/SAP. 6.1.2.1 Downloading WSDL and XSD Web services are usually defined via WSDL (Web Service Definition Language). A WSDL file is an XML file, which defines the API of a Web service provider. For example, it specifies the available methods and the respective parameters. A WSDL file can be accompanied by one or more XSD (XML Schema Definition) files. XSD files define XML tags and attributes that are used in the WSDL file. This way, data types can be defined in a generic way. Note that this is a very simplified view on WSDL and XSD. More information on this topic is widely available on the Internet. Here are the sources for the PayPal WSDL file and XSD files: Location for PayPal Sandbox Web Service Definition https://www.sandbox.paypal.com/wsdl/PayPalSvc.wsdl XML Schema Definition https://www.sandbox.paypal.com/wsdl/eBLBaseComponents.xsd https://www.sandbox.paypal.com/wsdl/CoreComponentTypes.xsd https://www.sandbox.paypal.com/wsdl/EnhancedDataTypes.xsd Location for PayPal Productive System Web Service Definition https://www.paypal.com/wsdl/PayPalSvc.wsdl XML Schema Definition http://www.paypal.com/wsdl/eBLBaseComponents.xsd http://www.paypal.com/wsdl/CoreComponentTypes.xsd http://www.paypal.com/wsdl/EnhancedDataTypes.xsd 6.1.2.2 Editing WSDL File Ideally, the WSDL file can be directly used for the generation of the Web service consumer. In practice, however, this is usually not possible. This has two reasons. First, there can be errors in the WSDL file. For example, this is the case for the files provided by PayPal. Second, there are limitations of the SAP Web Service Generation Tool. The following subsections show the necessary changes to the PayPal WSDL file. 1. Copy XML schema definition into WSDL. The web service proxy generation tool from SAP NetWeaver does not support mutually recursive schema imports in the WSDL. Mutually recursive schema imports cause an endless loop. The PayPal WSDL file references the two XSD files. The XSD files reference each other. Because of this mutually recursive import, the generation does not work. The workaround for this limitation is to copy the XML Schema Definitions into the WSDL file. This way there is no mutually recursive schema import anymore. The following two steps are necessary to do this. 1. Copy the contents of the XSD files into the wsdl:types section of the WSDL file 2. Remove the schemaLocation attributes which import the XSD files. Note This is a limitation of SAP Net Weaver. A fix might be provided in the future. October 2013 171 Development and Extension Guide – Application-Specific Information 2. Remove attribute version. If an XML element or attribute is not defined correctly, the generation of the web service proxy aborts with a syntax error. The attribute version in the PayPal WSDL file specifies the version of the PayPal API. The current version is ‘60.0’. Unfortunately, the attribute version is not defined and causes an exception in the library handler. The workaround for this error is to simply delete the attribute version from the WSDL file. Since this attribute only has informational purpose there are no technical consequences. Note This is an error in the PayPal WSDL file. This issue has been addressed to PayPal. 3. Change fixed length of payerID (in earlier versions of PayPal only). Parameters of methods specified in the WSDL file can be defined with a fixed length. This can cause issues in Web service communication because attribute values are filled with blanks. For example, if a parameter has the fixed length of 100 characters and the parameter value is shorter than 100 characters, then the remaining characters are filled with blanks. In the PayPal XSD file eBLBaseComponents.xsd, the data type UserIDType is defined with a fixed length of 127 characters. This data type is used for the PayerID. In practice, the payer ID is shorter than 127 characters. The blanks after the PayerID cause issues in the communication to PayPal because PayPal no longer recognizes the PayerID. For example, the PayPal API receives “PayerA “ which is not equal to “PayerA”. <simpleType> <restriction base="xs:string"> <length value="127" /> </restriction> </simpleType> The workaround for this error is to simply change the attribute length to maxLength. Then the parameter value can be up to the number of specified characters but also can be less. Note This is an error in the PayPal WSDL file. This issue has been solved by PayPal in later versions. 4. Make parameter EBAY_TRANSACTION_ID optional. Parameters can be specified in the WSDL file using a minimum and maximum occurrence. If the minimum occurrence is not specified, this means that it is one. Mandatory attributes have a minimum occurrence of one. If a mandatory attribute is not returned from the Web service, there will be an error in the XML transformation in the back end. The parameter EBAY_TRANSACTION_ID is not returned by PayPal in the method GET_TRANSACTION_DETAILS because it is not relevant here. However, it is marked in the WSDL file as mandatory and hence the XML transformation expects it to be returned. This causes an error when receiving a response from PayPal. The workaround for this error is to simply specify the minimum occurrence of zero for the parameter EBAY_TRANSACTION_ID in the PayPal WSDL file: 172 October 2013 Development and Extension Guide – Application-Specific Information <element ref="ns:EbayTransactionID" *minOccurs="0"*> <annotation> <documentation> Its Ebay transaction id. <br /> EbayTransactionID will returned for immediate pay item transaction in ECA </documentation> </annotation> </element> Note This is an error in the PayPal WSDL file. In different versions of PayPal, the exact syntax may differ. 6.1.2.3 Generating Web Service Proxy You can create a Web service consumer proxy using the following steps: 1. Enter transaction SE80. 2. Right-click on a package. Choose Create -> Enterprise Service. 3. Choose Service Consumer and then Continue. 4. Choose Local File and then Continue. 5. Enter C:\<Path>PayPalSvc.wsdl and choose Continue. 6. Choose Local Object. Enter the transport request and choose Continue. 7. Choose Complete. 8. Choose the first entry PayPalAPIInterface. 9. Activate the created Web service proxy. 10. Confirm the popup saying that the object name SOLUTION_TYPE is reserved for package SO. 11. Choose the Used Objects tab and scroll down to the object SOLUTION_TYPE_TYPE. 12. Change the object name from SOLUTION_TYPE_TYPE to PAYPAL_SOLUTION_TYPE_TYPE. 13. Repeat steps 1 to 9 but choose the second entry PayPalAPIAAInterface in step 8. October 2013 173 Development and Extension Guide – Application-Specific Information The following diagrams show an example of creating a Web service consumer proxy: 174 October 2013 Development and Extension Guide – Application-Specific Information October 2013 175 Development and Extension Guide – Application-Specific Information 176 October 2013 Development and Extension Guide – Application-Specific Information October 2013 177 Development and Extension Guide – Application-Specific Information 178 October 2013 Development and Extension Guide – Application-Specific Information October 2013 179 Development and Extension Guide – Application-Specific Information 180 October 2013 Development and Extension Guide – Application-Specific Information October 2013 181 Development and Extension Guide – Application-Specific Information 182 October 2013 Development and Extension Guide – Application-Specific Information The Web service proxy CO_PAY_PAL_APIAAINTERFACE is created by the proxy generation tool based on a WSDL file. All methods provided by a proxy can be easily shown in the External View and Internal View tabs. The External View tab shows the external (PayPal) view on the methods. The Internal View tab shows the internal (ABAP) view on the methods. Note A Web service proxy is a class. Its methods can be accessed just as in any other call of an ABAP class method. October 2013 183 Development and Extension Guide – Application-Specific Information 6.1.2.4 Creating Web Service Wrapper The Web service proxy is automatically created based on an XML file. The automatically created structures for the method parameters are usually very nested just like an XML document. This means that it is not very convenient to call a Web service proxy. Therefore, we recommend that you create a wrapper class for the proxy. A wrapper class has the following advantages: Encapsulates one or more Web service proxies Serves as an API for the Web service Provides convenient access to the functionality of the Web service Abstracts from the technical details (for example, nested structures) Only offers required parameters in its interface (not the complete list defined in the WSDL) Data mapping such as ISO conversions Error handling In the following example we assume that there is a wrapper class ZCL_COMMON_PAYPAL_API (not part of the SAP standard delivery) that encapsulates some Web service proxy functions. It serves as the API for the PayPal Web service. ISO Conversion The PayPal system can use ISO currency and language codes. Therefore, the SAP currency and SAP language need to be converted to ISO codes. You can do this with the following code: DATA: lv_iso_langu TYPE laiso, lv_iso_currency TYPE tcurc-isocd. TRY. * Convert language key to ISO language code CALL METHOD cl_gdt_conversion=>language_code_outbound EXPORTING im_value = sy-langu IMPORTING ex_value = lv_iso_langu. * Convert currency key to ISO currency code CALL METHOD cl_gdt_conversion=>currency_code_outbound EXPORTING im_value = iv_currency IMPORTING ex_value = lv_iso_currency. CATCH cx_gdt_conversion INTO le_gdt_conv. ls_message-type = 'E'. ls_message-message = le_gdt_conv->if_message~get_text( ). CALL FUNCTION 'OWN_LOGICAL_SYSTEM_GET' IMPORTING own_logical_system = ls_message-system. APPEND ls_message TO et_messages. CLEAR ls_message. ev_success = abap_false. RETURN. ENDTRY. 184 October 2013 Development and Extension Guide – Application-Specific Information Call to the Proxy Calling a method of the proxy is just like calling a normal class method. Each method of the proxy has the following parameters: The parameter INPUT is an importing parameter and is a structure containing all parameters that are sent to the Web service. The parameter OUTPUT is an exporting parameter and is a structure containing all parameters that are returned from the Web service. The following is an exemplary code excerpt from the method ZZCL_COMMON_PAYPAL_API=>SET_EXPRESS_CHECKOUT. DATA: lo_ws_proxy TYPE REF TO co_pay_pal_apiaainterface. […] * Call webservice proxy TRY. CALL METHOD lo_ws_proxy->set_express_checkout EXPORTING input = ls_request IMPORTING output = ls_response. CATCH cx_ai_system_fault INTO le_system_fault. lv_text = le_system_fault->if_message~get_text( ). MESSAGE lv_text TYPE 'E'. CATCH cx_ai_application_fault INTO le_app_falut. lv_text = le_app_falut->if_message~get_text( ). MESSAGE lv_text TYPE 'E'. ENDTRY. Error Handling There are two kinds of errors: Errors that occur on SAP side (application error or system error) Errors that occur on PayPal side You must detect and deal with both types of errors. The following code detects an error on SAP side, returns the error with the message text, and aborts in case of an error: * Call webservice proxy TRY. CALL METHOD lo_ws_proxy->set_express_checkout EXPORTING input = ls_request IMPORTING output = ls_response. CATCH cx_ai_system_fault cx_ai_application_fault INTO le_root. ls_message-type = 'E'. ls_message-message = le_app_falut->if_message~get_text( ). CALL FUNCTION 'OWN_LOGICAL_SYSTEM_GET' IMPORTING own_logical_system = ls_message-system. APPEND ls_message TO et_messages. October 2013 185 Development and Extension Guide – Application-Specific Information CLEAR ls_message. ev_success = abap_false. RETURN. ENDTRY. The following code detects an error that was returned from PayPal and returns the errors with the message texts: method GET_ERRORS_FROM_PAYPAL. DATA: ls_message TYPE bapiret2. FIELD-SYMBOLS: <ls_paypal_error> TYPE error_type3. * Error detection CASE is_abstract_response_type-ack. WHEN gc_ack_success. ev_success = abap_true. WHEN gc_ack_successwithwarning. ev_success = abap_true. WHEN gc_ack_failure. ev_success = abap_false. WHEN gc_ack_failurewithwarning. ev_success = abap_false. * For the values below we cannot be really sure whether the operation was successful. * Therefore, the parameter returned by PayPal is checked. If it is provided, the * operation was successful - otherwise it failed. For example, if the method * set_express_checkout returns with a warning but the token is returned from * PayPal, the operation was a success. WHEN gc_ack_warning. IF iv_returned_value IS INITIAL. ev_success = abap_false. ELSE. ev_success = abap_true. ENDIF. WHEN gc_ack_customcode. "Reserved by PayPal for internal or future use IF iv_returned_value IS INITIAL. ev_success = abap_false. ELSE. ev_success = abap_true. ENDIF. WHEN OTHERS. IF iv_returned_value IS INITIAL. ev_success = abap_false. ELSE. ev_success = abap_true. ENDIF. 186 October 2013 Development and Extension Guide – Application-Specific Information ENDCASE. * Loop over all messages returned from PayPal LOOP AT is_abstract_response_type-errors ASSIGNING <ls_paypal_error>. CASE <ls_paypal_error>-severity_code. WHEN gc_severity_code_warning. ls_message-type = 'W'. WHEN gc_severity_code_error. ls_message-type = 'E'. WHEN gc_severity_code_custom. "Reserved by PayPal for internal or future use ls_message-type = 'I'. ENDCASE. ls_message-message = <ls_paypal_error>-short_message. APPEND ls_message TO et_messages. CLEAR ls_message. ENDLOOP. endmethod. The application that calls the Web service wrapper receives the exporting parameter EV_SUCCESS, which indicates the success of the operation, and it receives the exporting parameter ET_MESSAGES, which contains all error messages. The system needs to handle the errors. For example, the system can log the error messages and inform the Web shop customer that the operation is aborted. Caution If PayPal returns an error, PayPal usually does not return any parameter values. For example, if the authentication fails, PayPal does not return a token in method SET_EXPRESS_CHECKOUT. Many returning parameters such as the token are marked as mandatory in the WSDL file. If a mandatory parameter is not returned by PayPal, the XML transformation (XSLT) in SAP NetWeaver aborts with the exception cx_ai_system_fault. This makes it impossible to get the error message returned from PayPal with the coding above. Therefore, it will be necessary either to trace the XML response in the XML Monitor (transaction SXMB_MONI) or to debug to the code that processes the XML response. Note that this is an error in the WSDL file from PayPal. This is not an error in SAP NetWeaver. PayPal does not return attributes that are marked as mandatory in the WSDL file. Therefore, those parameters should be marked as optional in the WSDL file from PayPal. For many attributes, PayPal does not specify the occurrence of a parameter. According to the World Wide Web Consortium (W3C), “The default value for both the minOccurs and the maxOccurs attributes is 1.” http://www.w3.org/TR/xmlschema-0/ This means that parameters are mandatory if the occurrence is not specified. PayPal might have mistakenly forgotten to specify those parameters as optional. For more information about error handling, see https://cms.paypal.com/us/cgi-bin/?cmd=_render- content&content_ID=developer/e_howto_api_nvp_errorcodes. October 2013 187 Development and Extension Guide – Application-Specific Information Additional Attributes in SOAP Header A normal call to the proxy only fills the data in the body of a SOAP message. The SOAP header is created automatically. Sometimes it is required to add additional data to the header of a SOAP message. Note SOAP is an XML format used in Web service communication. More information on SOAP is widely available on the Internet. For example, many Web service providers require an authentication via the SOAP header. This means that the user name and password are transmitted in the header of the SOAP message. Caution SOAP messages can be traced, for example via the XML Monitor (transaction SXMB_MONI) and via an ICF (Internet Communication Framework) trace. Users with the required authorization for such tracing tools can view SOAP messages in plain text. Therefore, it is not compliant with the SAP security standard to send credentials via the SOAP header in plain text. The same applies for the SOAP body. Authentication via the SOAP header is a proprietary security mechanism. Therefore it is not supported out of the box by SAP NetWeaver. SAP supports the Web Service Security protocol, which is the standard security mechanism for Web service calls. Caution PayPal requires authentication via signature and certificate. User name and Password (signature) must be sent in the SOAP header in plain text. This security issue has been addressed to PayPal. The certificate is not part of SOAP header. For more information, see section Import Client Certificate. The following coding shows how to generate the additional data for the SOAP header using the SAP NetWeaver iXML library and how to put it into the SOAP header. Note that knowledge about XML and about DOM (Document Object Model) is required to understand the coding. Information on XML and DOM is widely available on the Internet. method GET_WS_INTERFACE. DATA: lr_protocol TYPE REF TO if_wsprotocol_ws_header, lr_xml_document TYPE REF TO if_ixml_document. DATA: le_system_fault TYPE REF TO cx_ai_system_fault, lv_text TYPE string. TRY. * Create instance CREATE OBJECT er_interface EXPORTING logical_port_name = iv_logical_port. * Get the web service protocol for access to additional fields of the WS SOAP message header lr_protocol ?= er_interface->get_protocol( if_wsprotocol=>ws_header ). 188 October 2013 Development and Extension Guide – Application-Specific Information * Get additional fields for the authentication in the SOAP header CALL METHOD get_soap_header_auth EXPORTING iv_username = iv_username iv_password = iv_password iv_signature = iv_signature IMPORTING er_xml_document = lr_xml_document. * Add additional fields to the SOAP header CALL METHOD add_to_soap_header EXPORTING ir_xml_document = lr_xml_document ir_protocol = lr_protocol. CATCH cx_ai_system_fault INTO le_system_fault. lv_text = le_system_fault->if_message~get_text( ). MESSAGE lv_text TYPE 'X'. ENDTRY. endmethod. METHOD get_soap_header_auth. CONSTANTS: co_tag_header TYPE string VALUE 'Header', "#EC NOTEXT co_tag_req_cred TYPE string VALUE 'RequesterCredentials', "#EC NOTEXT co_tag_credentials TYPE string VALUE 'Credentials', "#EC NOTEXT co_tag_username TYPE string VALUE 'Username', "#EC NOTEXT co_tag_password TYPE string VALUE 'Password', "#EC NOTEXT co_tag_signature TYPE string VALUE 'Signature', "#EC NOTEXT co_attr_xmlns TYPE string VALUE 'xmlns', "#EC NOTEXT co_attr_type TYPE string VALUE 'type', "#EC NOTEXT co_namesp_soap TYPE string VALUE 'SOAP-ENV', "#EC NOTEXT co_namesp_xsi TYPE string VALUE 'xsi', "#EC NOTEXT co_ns_paypalapi TYPE string VALUE 'urn:ebay:api:PayPalAPI', "#EC NOTEXT co_ns_eblbase TYPE string VALUE 'urn:ebay:apis:eBLBaseComponents', "#EC NOTEXT co_ns_xsi TYPE string VALUE 'http://www.w3.org/2001/XMLSchema-instance', "#EC NOTEXT co_ns_enc TYPE string VALUE 'http://schemas.xmlsoap.org/soap/encoding/', "#EC NOTEXT co_ns_env TYPE string VALUE 'http://schemas.xmlsoap.org/soap/envelope/', "#EC NOTEXT co_ns_xsd TYPE string VALUE 'http://www.w3.org/2001/XMLSchema', "#EC NOTEXT co_ns_encoding TYPE string VALUE 'http://schemas.xmlsoap.org/soap/encoding/', "#EC NOTEXT co_ns_security_h TYPE string VALUE 'ebl:CustomSecurityHeaderType', "#EC NOTEXT October 2013 189 Development and Extension Guide – Application-Specific Information co_ns_base_comp TYPE string VALUE 'urn:ebay:apis:eBLBaseComponents', "#EC NOTEXT co_ns_user_pwd TYPE string VALUE 'ebl:UserIdPasswordType'. "#EC NOTEXT DATA: l_ixml TYPE REF TO if_ixml, l_document TYPE REF TO if_ixml_document, l_encoding TYPE REF TO if_ixml_encoding, l_root TYPE REF TO if_ixml_element, l_req_cred TYPE REF TO if_ixml_element, l_credentials TYPE REF TO if_ixml_element, l_username TYPE REF TO if_ixml_element, l_password TYPE REF TO if_ixml_element, l_signature TYPE REF TO if_ixml_element, l_rc LIKE sy-subrc, l_streamfactory TYPE REF TO if_ixml_stream_factory, l_stream TYPE REF TO if_ixml_ostream, l_renderer TYPE REF TO if_ixml_renderer, l_xstring TYPE xstring. * Initialize the iXML-Toolkit l_ixml = cl_ixml=>create( ). * Create the xml-document l_document = l_ixml->create_document( ). * Set encoding to UTF-8 l_encoding = l_ixml->create_encoding( byte_order = 0 " little endian byte ordering character_set = 'UTF-8' ). CALL METHOD l_document->set_encoding EXPORTING encoding = l_encoding. * Create the root element (SOAP header) l_root = l_document->create_simple_element( name = co_tag_header namespace = co_namesp_soap parent = l_document ). * Create the element RequesterCredentials l_req_cred = l_document->create_simple_element( name = co_tag_req_cred parent = l_root ). * Create the element Credentials l_credentials = l_document->create_simple_element( 190 October 2013 Development and Extension Guide – Application-Specific Information name = co_tag_credentials parent = l_req_cred ). * Create the element Username l_username = l_document->create_simple_element( name = co_tag_username value = iv_username parent = l_credentials ). * Create the element Password l_password = l_document->create_simple_element( name = co_tag_password value = iv_password parent = l_credentials ). * Create the element Signature IF iv_signature IS NOT INITIAL. l_signature = l_document->create_simple_element( name = co_tag_signature value = iv_signature parent = l_credentials ). ENDIF. * Add attributes to the elements l_rc = l_req_cred->set_attribute( name = co_attr_xmlns value = co_ns_paypalapi ). l_rc = l_req_cred->set_attribute( "xmlns:xsi= name = co_namesp_xsi namespace = co_attr_xmlns value = co_ns_xsi ). l_rc = l_req_cred->set_attribute( name = co_attr_type namespace = co_namesp_xsi value = co_ns_security_h ). l_rc = l_credentials->set_attribute( name = co_attr_xmlns value = co_ns_base_comp ). l_rc = l_credentials->set_attribute( name = co_attr_type namespace = co_namesp_xsi value = co_ns_user_pwd ). er_xml_document = l_document. ENDMETHOD. October 2013 191 Development and Extension Guide – Application-Specific Information method ADD_TO_SOAP_HEADER. DATA: l_root TYPE REF TO if_ixml_element, l_element TYPE REF TO if_ixml_element. DATA: lv_element_name TYPE string, lv_namespace TYPE string. * Get root element l_root = ir_xml_document->get_root_element( ). * Get first child element l_element ?= l_root->get_first_child( ). * Loop over all child elements WHILE NOT l_element IS INITIAL. * Get element name and namespace lv_element_name = l_element->get_name( ). lv_namespace = l_element->get_namespace_uri( ). * Add header element to SOAP header ir_protocol->set_request_header( name = lv_element_name namespace = lv_namespace dom = l_element ). * Get next element l_element ?= l_element->get_next( ). ENDWHILE. endmethod. The following example shows what the XML data added to the SOAP header looks like: <RequesterCredentials xmlns=”urn:ebay:api:PayPalAPI” xsi:type=”ebl:CustomSecurityHeaderType”> <Credentials xmlns=”urn:ebay:apis:eBLBaseComponents” xsi:type=”ebl:UserIdPasswordType”> <Username>api_username</Username> <Password>api_password</Password> <Signature>api_signature</Signature> </Credentials> </RequesterCredentials> Caution The data must be added to the SOAP header before each call to the proxy. It is not sufficient to add the data to the variable lr_protocol (see coding above) only once. 192 October 2013 Development and Extension Guide – Application-Specific Information 6.1.2.5 Regenerating Web Service Proxy It might be necessary to make changes to the WSDL file after the proxy was already generated. For example, there could be an error in the file that was not identified at the time of the proxy generation. In such a case, there is no need to start from scratch. The Web service proxy can be regenerated with the following steps: 1. Enter transaction SE80. 2. Enter package COM_WEC_PAYPAL_IMPL. 3. Open the service consumer CO_PAY_PAL_APIINTERFACE. 4. Choose Regenerate. 5. Choose Local File. 6. Enter the location of the modified WSDL document. 7. Choose Complete. 8. Activate the proxy. The following figures show how you can regenerate the Web service proxy: October 2013 193 Development and Extension Guide – Application-Specific Information 194 October 2013 Development and Extension Guide – Application-Specific Information October 2013 195 Development and Extension Guide – Application-Specific Information 196 October 2013 Development and Extension Guide – Application-Specific Information October 2013 197 Development and Extension Guide – Application-Specific Information 6.1.2.6 Setting Up Connection to PayPal (Customizing) Logical Port Configuration You can create a logical port using the following steps: 1. Enter transaction SE80. 2. Enter package COM_WEC_PAYPAL_IMPL. 3. Open the service consumer CO_PAY_PAL_APIINTERFACE. 4. Choose Start SOAMANAGER. Alternatively, start transaction SOAMANAGER and search for the service consumer. 5. Select the service consumer and choose Apply Selection. 6. Choose Configurations. 7. Choose Create Logical Port. 8. Enter the name of the logical port and a description. 9. Select the Logical Port is Default check box. (Otherwise, you must specify the name of the logical port in the coding.) 10. To generate the logical port automatically from the WSDL file from PayPal, choose WSDL Based Configuration and enter the location of the WSDL file. 11. Choose Apply Settings. The system automatically creates the configuration for the logical port. You can change the configuration, if necessary. 198 October 2013 Development and Extension Guide – Application-Specific Information 12. Choose the Transport Settings tab. 13. Verify that the generated settings match the correct PayPal API endpoints. 14. Enter the proxy host and port, for example proxy and 8080. Caution The proxy proxy could also be an IP address. No ‘http://’ must be specified in the proxy field. Note The proxy of the Web shop owner must be entered. Therefore, this information cannot be provided by PayPal in the WSDL file. PayPal does not know the proxy of any Web shop owner. 15. Choose Save. 16. Repeat steps 1 to 15 for the service consumer CO_PAY_PAL_APIAAINTERFACE. Note A logical port always belongs to one service consumer. Therefore, there can be two logical ports with the same name but for different service consumers. October 2013 199 Development and Extension Guide – Application-Specific Information The following figures show an example of how you can create a logical port: 200 October 2013 Development and Extension Guide – Application-Specific Information October 2013 201 Development and Extension Guide – Application-Specific Information 202 October 2013 Development and Extension Guide – Application-Specific Information October 2013 203 Development and Extension Guide – Application-Specific Information 204 October 2013 Development and Extension Guide – Application-Specific Information October 2013 205 Development and Extension Guide – Application-Specific Information 206 October 2013 Development and Extension Guide – Application-Specific Information Setup of Secure Connection The following sections examine the steps to set up a secure connection with PayPal. 1. Import Server Certificate A Secure Socket Layer (SSL) connection to a server can only be established if the server is trusted. Therefore, it is necessary to install the server certificate from PayPal via transaction STRUST. Note A server certificate is provided by the server but it is no means of authentication required by the server. Its purpose is that the caller (SAP system in our case) trusts the server (PayPal in our case). Note that browsers such as the Internet Explorer make use of server certificates also. The difference to a SAP system is that the Internet Explorer downloads the server certificate automatically whereas in an SAP system is has to be explicitly installed for security reasons. If the server certificate is not installed correctly, the following error message will be issued when connecting to the server (PayPal in this case): "ICF Error when receiving the response: ICM_HTTP_SSL_ERROR". Download the server certificate from PayPal and install it on the SAP back-end system as follows: a. Point your browser to the PayPal homepage www.paypal.com. b. Choose the lock symbol in the lower right corner of the browser. c. Export the certificate (save it to your hard drive). d. Import this certificate into your SAP system (transaction STRUST). October 2013 207 Development and Extension Guide – Application-Specific Information The following figure shows the location of the lock symbol in a Web browser: 208 October 2013 Development and Extension Guide – Application-Specific Information The following figures show an example of how to import a certificate: October 2013 209 Development and Extension Guide – Application-Specific Information Caution The server certificate needs to be installed to the SSL Client Standard, not to the SSL Server Standard. The server certificate is only valid in a certain time period (see first screenshot below). Therefore, it is recommended to install the VeriSign Root Certificate. This means only to import the first two levels of the certification path (see second screenshot below). Otherwise, the certificate would have to be replaced each time before its validity ends. 210 October 2013 Development and Extension Guide – Application-Specific Information October 2013 211 Development and Extension Guide – Application-Specific Information 2. Import Client Certificate Caution Importing the client certificate will not work without the complete certificate chain. Intermediate certificates are owned only by PayPal. Ask PayPal for these certificates. A client certificate is a means of authentication. The client certificate uniquely identifies the client (for example, the SAP system of a Web shop owner) and is used by the server (for example, PayPal) to authenticate the client. PayPal authenticates as follows: The system authenticates using a username, password, and a signature in the SOAP header. This process is easier to implement and can be used for testing against the PayPal sandbox system. The system authenticates using a username and a password in the SOAP header and, additionally, the client certificate. This process is more secure and can be used for productive use. The second option provides additional security. The disadvantage of the second option is the additional effort of installing the client certificate. Caution Providing any credentials in the SOAP header in plain text is not secure because this data can be traced, for example in the XML Monitor (transaction SXMB_MONI) or in the ICF recorder. Therefore, neither the first nor the second options meet SAP security standards. 212 October 2013 Development and Extension Guide – Application-Specific Information Download the client certificate from PayPal and install it in the SAP system as follows: a. Open a Web browser. b. Go to your PayPal merchant account. c. Download the PayPal client certificate. d. Import this certificate into your SAP system (transaction STRUST). e. Import all intermediate certificates of the certificate chain from the downloaded one to the root certification authority. Caution All PayPal intermediate certificates are needed. Additional information from PayPal: Requesting an API Certificate: https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/apicertificates 3. (If Applicable) Configure HTTP Destination Note In later versions, the destination concept was deprecated. Configure the HTTP Destination as follows to support SSL encryption: a. Open the logical port for the service consumer CO_PAY_PAL_APIINTERFACE. b. Choose the Additional Information tab. c. Copy the HTTP destination. d. Enter RFC and HTTP destinations (transaction SM59). e. Search for the HTTP destination that you copied previously. f. Choose the Logon & Security tab. g. Choose the Default SSL Client SSL certificate. h. Save your entries. i. Repeat this procedure for the logical port of the service consumer CO_PAY_PAL_APIAAINTERFACE. October 2013 213 Development and Extension Guide – Application-Specific Information The following figures show an example of how you can configure the HTTP destination. 214 October 2013 Development and Extension Guide – Application-Specific Information October 2013 215 Development and Extension Guide – Application-Specific Information 216 October 2013 Development and Extension Guide – Application-Specific Information October 2013 217 Development and Extension Guide – Application-Specific Information 4. Test connection Test the connection to the PayPal Web service as follows: a. Enter transaction SM59. b. Open the HTTP connection for the logical port. c. Test the connection. If the logical port, the HTTP connection, the server certificate, and the client certificate are set up correctly, an HTTP response should be received (see second screenshot below). Caution The test needs to be executed for each logical port. There are two logical ports for the PayPal integration. Note It does not matter if errors are returned in the status text, the response body, or the response text (see third screenshot below). No actual data is transferred to the Web service. Therefore, it is likely that an error is returned. This is not a problem. The connection test only shows whether the connection between the SAP system and the PayPal system is working. Note If you get an error or you do not get a response, the connection is not set up correctly. In most cases, the server or client certificate is not imported correctly or the proxy settings in the logical port are not correct. 218 October 2013 Development and Extension Guide – Application-Specific Information October 2013 219 Development and Extension Guide – Application-Specific Information If the logical port, the HTTP connection, the server certificate, and the client certificate are set up correctly, an HTTP response should be received as shown in the following figure: 220 October 2013 Development and Extension Guide – Application-Specific Information It does not matter if errors are returned in the status text, the response body, or the response text as shown in the following figure (No data is transferred to the Web service). 6.1.2.7 Best Practices for Debugging Check XML Sent to Web Service Check the XML that will be sent to the Web service in the debugger tTranslate ABAP to XML request) as follows: 1. Set a breakpoint in the class method CL_SOAP_MESSAGE_NEW-> IF_SOAP_MESSAGE_PART~SERIALIZE in line 200. 2. Choose F6 to execute the method GET_XML_WRITER_OUTPUT. 3. Check the parameter XMLOUT. 4. Change the view of the parameter value to XML. The following figure shows the SOAP message sent to the Web service: October 2013 221 Development and Extension Guide – Application-Specific Information The following figure shows where you change the view of the parameter value to XML: 222 October 2013 Development and Extension Guide – Application-Specific Information Checking XML Received from Web Service Check the XML that was received from the Web service in the debugger (translate XML response to ABAP) as follows: 1. Set a breakpoint in the class method CL_SXMLP_LIST->_READ_CHILDREN in line 26. 2. Do not execute the method DESERIALIZE yet. 3. Check the READER parameter. 4. Check the M_INPUT attribute of the parameter. 5. Change the view of the attribute value to XML. The system shows the SOAP message that was received from the Web service. The following figure shows line 26 and the reader parameter in the debugger: October 2013 223 Development and Extension Guide – Application-Specific Information The following figure shows the M_INPUT attribute: 224 October 2013 Development and Extension Guide – Application-Specific Information The following figure shows where you change the view of the attribute value to XML: October 2013 225 Development and Extension Guide – Application-Specific Information 6.1.2.8 Tips This section provides helpful tips when errors occur in the Web service integration. 6.1.2.8.1 Issues with Web Service Proxy Generation The subsections below examine common errors during the Web service proxy generation and how they can be fixed. Infinite Loop in WSDL Parser Should the WSDL parser not return, this is most likely due to an infinite loop because of mutual schema imports. Syntax Error: Invalid Attribute If the following exception is returned during the proxy generation, this is most likely due to an XML attribute that is not defined correctly in the WSDL document (see technical section): “Exception occurred in library handler Illegal syntax: Element definitions has invalid enhancement attribute urn:ebay:api:PayPalAPI:version" The following figure shows the exception in the Object Navigtor: 226 October 2013 Development and Extension Guide – Application-Specific Information No Use Access for Objects from Another Package If the following error is returned when activating the proxy, this is most likely due to missing package interfaces: “Package Check for Table/Structure ABSTRACT_REQUEST_TYPE The object TABL ABSTRACT_REQUEST_TYPE uses DTEL XSDANY Data Element XSDANY There is no use access for the object from another structure package” The following figure shows the syntax error: To solve this issue, add the following on the User Access tab of both the package and the structure package: SABP_TRFO: Data element XSDANY and XSDDATETIME_Z SAI_PROXY_PUBLIC: Table type PRXCTRLTAB 6.1.2.8.2 Issues with Firewalls The IP address for PayPal servers is as follows: https://ppmts.custhelp.com/app/answers/detail/a_id/92 October 2013 227 Development and Extension Guide – Application-Specific Information 6.1.2.8.3 Issues with Web Service Proxies The following subsections explain common errors during Web service communication and how they can be fixed. Issue with Mandatory Attributes Parameters can be specified in the WSDL file using a minimum and maximum occurrence. If the minimum occurrence is not specified, this means that it equals one. Mandatory attributes have a minimum occurrence of one. This information is used by the Web service proxy and is shown in the following figure: If a mandatory parameter is not passed to the Web service proxy, there will be an error. This can be fixed easily by passing the parameter. If a mandatory parameter is not returned from the Web service, there will be an error in the XML transformation in the back end (in the case of the parameter EBAY_TRANSACTION_ID, this is an error in the PayPal WSDL file). The parameter is not returned by PayPal in the method GET_TRANSACTION_DETAILS because it is not relevant there. However, it is marked in the WSDL file as mandatory and hence the XML transformation expects it to be returned. The workaround for this issue is to enter a minimum occurrence of zero for the attribute zero (see technical section). SSL Connection Issue If the following error is returned when making a connection to the Web service, this is because the secure connection is not set up correctly (see Customizing section). Check whether the server certificate was installed successfully in transaction STRUST. “SOAP:1.023 SRT: Processing error in Internet Communication Framework: ("ICF Error when receiving the response: ICM_HTTP_SSL_ERROR")” 228 October 2013 Development and Extension Guide – Application-Specific Information 6.1.3 SAP ERP E-Commerce In the E-Commerce SAP ERP back end scenario, order management, order fulfillment, billing, and financials are completed in the SAP ERP back end. You do all configuration and BAdI implementation in the SAP ERP back end. The following figure shows the scenario: The order in the SAP ERP back end gets status information from the payment service provider using the payment service provider interface (PSP IF). The system passes status information by way of billing to financials where settlement takes place. October 2013 229 Development and Extension Guide – Application-Specific Information Consider the following activities when using the E-Commerce SAP ERP back-end integration scenario. 1. Activate business function in the SAP ERP back end. Activate the ERP_WEB_CHANNEL_1 business function. 2. Maintain Customizing for PSP integration in the SAP ERP back end. Make the settings in Customizing for SAP ERP under Sales and Distribution -> SAP Web Channel Experience Management -> Payment Service Prov. 3. Implement BAdI Integration of Payment Service Providers in the SAP ERP back end. Make sure you make the settings in Customizing for SAP ERP under Sales and Distribution -> SAP Web Channel Experience Management -> Payment Service Prov. -> Business Add-Ins (BAdIs). As a prerequisite, you must have already implemented all relevant proxy calls to the Web services provided by the payment service provider (see subsection Call to the Proxy in section Creating Web Service Wrapper). For more information, see Sample Implementation of BAdI 'Integration of Payment Service Providers' in the SAP ERP Back End. 4. Implement BAdI Import Settlement Files for Each Payment Service Provider. You can use this BAdI to import settlement files from different payment service providers into the system. Further processing takes place in the electronic account statement. The BAdI is always called when a user executes the following transaction: Import Settlement File of Payment Service Provider (transaction FEBPS). To import the settlement file, the READ_PAYSP_SETTLEMENT_FILE method must be implemented. The payment service provider's ID serves as a filter value in the implementation. Caution PayPal requires activation to receive the settlement file. In addition, you must enter an FTP user and password. For more information, see Sample Implementation of BAdI 'Import Settlement Files for Each Payment Service Provider'. 5. Schedule periodic tasks in the SAP ERP back end. Use program SLS_LPAYSP_DOCUMENT_UPDATE (transaction VPP1) to identify and process incomplete sales orders and service orders in the SAP ERP back end that Web shop customers create using payment service providers. For more information, see the online documentation for the program. 230 October 2013 Development and Extension Guide – Application-Specific Information 6.1.3.1 Sample Implementation of BAdI 'Import Settlement Files for Each Payment Service Provider' The following code is an example for IF_EX_FPS_IMPORT_PAYSP_FILE~READ_PAYSP_SETTLEMENT_FILE. method IF_EX_FPS_IMPORT_PAYSP_FILE~READ_PAYSP_SETTLEMENT_FILE. data: l_t_auszug type zfps_t_char800, lsep(3) type c, lsep1(2) type c, lsep2(2) type c, sart(2) type c, ls_t012k type t012k, l_db_cr_ind(2), l_db_cr_ind_fee(2), l_curr_iso(3), l_date(8), l_waer type waers, l_betrag type ssbtr_eb, field_tab type zpaypal_t_char35, ls_field_type type zpaypal_char35, value_tab type zpaypal_t_value, ls_value type zpaypal_value, ls_febko type febko, l_count type i value 0, l_absnd(50), ls_auszug type fps_header, ls_umsatz type fps_item, ls_bapiret type bapiret2, l_item_count type i value 0. field-symbols: <line> type any. *------------------------------------------------------------------------------------------ refresh: et_items, et_header. clear: ls_t012k, ls_auszug. *--- Upload File CALL METHOD me->upload_data EXPORTING i_pfname = i_pfname IMPORTING e_auszug = l_t_auszug. check not l_t_auszug is initial. *--- CALL FUNCTION 'GET_BANK_ACCOUNT' EXPORTING i_bankl = i_bank i_bankn = i_account IMPORTING e_t012k = ls_t012k EXCEPTIONS October 2013 231 Development and Extension Guide – Application-Specific Information input_wrong = 1 bank_account_not_found = 2 bank_key_false = 3 bank_key_not_found = 4 currency_false = 5 currency_not_found = 6 multiple_bank_account = 7 account_type_false = 8 account_type_not_found = 9 others = 10. if sy-subrc = 0. CALL METHOD me->determine_decimals EXPORTING i_waers = ls_t012k-waers. move ls_t012k-waers to ls_auszug-waers. l_absnd(15) = i_bank. l_absnd+15 = i_account. l_absnd+45 = ls_t012k-waers. *-- Statement number not provided => take last statement no + 1 -- select * from febko into ls_febko where anwnd = '0001' and absnd = l_absnd order by aznum descending. exit. endselect. if sy-subrc <> 0. "First Stmt ls_auszug-aznum = 1. "Set Stmt Number else. ls_auszug-aznum = ls_febko-aznum + 1. "Set Statement Number endif. else. exit. endif. if not ls_febko is initial. *-- START SALDO *-- make end saldo of the previous statement as new start saldo of of the current statement move ls_febko-esbtr to ls_auszug-ssald. if ls_febko-esvoz = 'S'. multiply ls_auszug-ssald by -1. endif. endif. ls_auszug-bank = i_bank. ls_auszug-ktonr = i_account. concatenate '"' gd_separator '"' into lsep. concatenate '"' gd_separator into lsep1. concatenate gd_separator '"' into lsep2. *-------------------------------------------------------------------------------------- loop at l_t_auszug assigning <line>. 232 October 2013 Development and Extension Guide – Application-Specific Information *-- clean-up line from the redundant characters while sy-subrc = 0. replace lsep1 with gd_separator into <line>. endwhile. sy-subrc = 0. while sy-subrc = 0. replace lsep2 with gd_separator into <line>. endwhile. if <line>+0(1) = '"'. shift <line> left by 1 places. endif. sy-subrc = 0. while sy-subrc = 0. replace '"' with '' into <line>. endwhile. sart = <line>+0(2). if sart = 'SH'. add 1 to l_count. if l_count ne 1. *--- only one paypal file is processed exit. endif. clear: value_tab[]. split <line> at gd_separator into table value_tab. loop at value_tab into ls_value. case sy-tabix. when '2'. if not ls_value-content is initial. clear l_date. l_date(4) = ls_value-content(4). l_date+4(2) = ls_value-content+5(2). l_date+6(2) = ls_value-content+8(2). move l_date to ls_auszug-azdat. endif. endcase. endloop. endif. *---- Get Variable names if sart = 'CH'. clear field_tab[]. split <line> at gd_separator into table field_tab. endif. *---- Get values of the variables if sart = 'SB'. add 1 to l_item_count. clear: value_tab[], ls_umsatz. split <line> at gd_separator into table value_tab. clear l_db_cr_ind. loop at value_tab into ls_value. read table field_tab into ls_field_type index sy-tabix. October 2013 233 Development and Extension Guide – Application-Specific Information check sy-subrc = 0. case ls_field_type-name. when 'InvoiceID'. if not ls_value-content is initial. move ls_value-content to ls_umsatz-vwz01. endif. when 'TransactionID'. if not ls_value-content is initial. move ls_value-content to ls_umsatz-vwz03. endif. when 'CustomField'. "GUID if not ls_value-content is initial. move ls_value-content to ls_umsatz-vwz02. endif. when 'TransactionDebitOrCredit'. if not ls_value-content is initial. move ls_value-content to l_db_cr_ind. endif. when 'GrossTransactionCurrency'. *-- conversion from iso to sap if not ls_value-content is initial. move ls_value-content to l_curr_iso. CALL FUNCTION 'CURRENCY_CODE_ISO_TO_SAP' EXPORTING iso_code = l_curr_iso IMPORTING sap_code = l_waer. if l_waer ne ls_auszug-waers. break ayat. MESSAGE e001(ZPAYPAL) WITH l_waer ls_t012k-waers l_item_count . endif. move l_waer to ls_umsatz-waers. endif. when 'GrossTransactionAmount'. if not ls_value-content is initial. * move ls_value-content to ls_umsatz-WRBTR. clear l_betrag. CALL METHOD me->trunc_decimals EXPORTING amount = ls_value-content IMPORTING e_amount = l_betrag. move l_betrag to ls_umsatz-wrbtr. endif. when 'TransactionEventCode'. *T0006 Express Checkout APIs (incoming payment at merchant) 234 October 2013 Development and Extension Guide – Application-Specific Information *T1107 Payment Refund initiated by merchant (triggered by cancellation) if ls_value-content = 'T0006' or ls_value-content = 'T1107'. move ls_value-content to ls_umsatz-gcode. else. clear ls_umsatz. continue. endif. when 'TransactionCompletionDate'. if not ls_value-content is initial. clear l_date. l_date(4) = ls_value-content(4). l_date+4(2) = ls_value-content+5(2). l_date+6(2) = ls_value-content+8(2). move l_date to: ls_umsatz-valut, ls_umsatz-bvdat. endif. *FeeDebitOrCredit when 'FeeDebitOrCredit'. if not ls_value-content is initial. move ls_value-content to l_db_cr_ind_fee. endif. *FeeAmount when 'FeeAmount'. if not ls_value-content is initial. clear l_betrag. CALL METHOD me->trunc_decimals EXPORTING amount = ls_value-content IMPORTING e_amount = l_betrag. move l_betrag to ls_umsatz-spesk. endif. *FeeCurrency endcase. endloop. if not ls_umsatz is initial. ls_umsatz-bank = ls_auszug-bank. ls_umsatz-ktonr = ls_auszug-ktonr. ls_umsatz-aznum = ls_auszug-aznum. if l_db_cr_ind = g_credit. ls_umsatz-wrbtr = ls_umsatz-wrbtr - ls_umsatz-spesk. add ls_umsatz-wrbtr to ls_auszug-sumha. elseif l_db_cr_ind = g_debit. ls_umsatz-wrbtr = ls_umsatz-wrbtr + ls_umsatz-spesk. add ls_umsatz-wrbtr to ls_auszug-sumso. multiply ls_umsatz-wrbtr by -1. endif. append ls_umsatz to et_items. October 2013 235 Development and Extension Guide – Application-Specific Information endif. endif. endloop. *-- END SALDO *-- SUM OF SUMHA&SUMSO&SSALD with signs into ESALD ls_auszug-esald = ls_auszug-ssald - ls_auszug-sumso + ls_auszug-sumha. if not et_items is initial. append ls_auszug to et_header. else. MESSAGE i002(ZPAYPAL). endif. endmethod. 6.1.3.2 Sample Implementation of BAdI 'Integration of Payment Service Providers' in the SAP ERP Back End The following code is a sample implementation. In this sample implementation, the Web service calls are encapsulated in class ZCL_COMMON_PAYPAL_API (see section Sample Implementation of BAdI 'Integration of Payment Service Providers' in the SAP CRM Back End). Sample BAdI Implementation ZCL_ERP_PAYPAL_IMPL: class ZCL_ERP_PAYPAL_IMPL definition public final create public . public section. *"* public components of class ZCL_ERP_PAYPAL_IMPL *"* do not include other source files here!!! interfaces IF_BADI_INTERFACE . interfaces IF_COM_WEC_PSP_INTEGRATION . protected section. *"* protected components of class ZCL_ERP_PAYPAL_IMPL *"* do not include other source files here!!! private section. *"* private components of class ZCL_ERP_PAYPAL_IMPL *"* do not include other source files here!!! types: begin of LTY_PSP_SHIPPIG_ADDRESS . types TITLE TYPE AD_TITLE. types NAME_FIRST TYPE AD_NAMEFIR. types NAME_LAST TYPE AD_NAMELAS. types NAME2_P TYPE AD_NAME2_P. types NAMEMIDDLE TYPE AD_NAMEMID. types NAME_LAST2 TYPE AD_NAMLAS2. types NICKNAME TYPE AD_NICKNAM. types INITIALS TYPE AD_INITS. types NAME1 TYPE AD_NAME1. types NAME2 TYPE AD_NAME2. 236 October 2013 Development and Extension Guide – Application-Specific Information types NAME3 TYPE AD_NAME3. types NAME4 TYPE AD_NAME4. types CITY1 TYPE AD_CITY1. types CITY2 TYPE AD_CITY2. types HOME_CITY TYPE AD_CITY3. types POST_CODE1 TYPE AD_PSTCD1. types POST_CODE2 TYPE AD_PSTCD2. types POST_CODE3 TYPE AD_PSTCD3. types PCODE1_EXT TYPE AD_PST1XT. types PCODE2_EXT TYPE AD_PST2XT. types PCODE3_EXT TYPE AD_PST3XT. types PO_BOX TYPE AD_POBX. types PO_BOX_NUM TYPE AD_POBXNUM. types PO_BOX_LOC TYPE AD_POBXLOC. types PO_BOX_REG TYPE AD_POBXREG. types PO_BOX_CTY TYPE AD_POBXCTY. types STREET TYPE AD_STREET. types HOUSE_NUM1 TYPE AD_HSNM1. types HOUSE_NUM2 TYPE AD_HSNM2. types HOUSE_NUM3 TYPE AD_HSNM3. types STR_SUPPL1 TYPE AD_STRSPP1. types STR_SUPPL2 TYPE AD_STRSPP2. types STR_SUPPL3 type AD_STRSPP3. types LOCATION type AD_LCTN. types BUILDING type AD_BLDNG. types FLOOR type AD_FLOOR. types ROOMNUMBER type AD_ROOMNUM. types COUNTRY type LAND1. types REGION type REGIO. types TAXJURCODE type AD_TXJCD. types end of LTY_PSP_SHIPPIG_ADDRESS . class-data GC_SIGNATURE type STRING value `YourPayPalTestAccountSignature`. "#EC NOTEXT . class-data GC_LOGICAL_PORT type PRX_LOGICAL_PORT_NAME value SPACE. "#EC NOTEXT . class-data GC_MESSAGE_ID type SYMSGID value 'ZERP_WEC_PAYPAL_IMPL'. "#EC NOTEXT . class-data GC_PAYPAL_CHECKOUT_URL type STRING value `https://www.sandbox.paypal.com/webscr&cmd=_express-checkout&token=`. "#EC NOTEXT . class-data GC_PAYPAL_PAYMENT_STATUS_COMP type COM_WEC_PAYPAL_PAYMENT_STATUS value `Completed`. "#EC NOTEXT . class-data GC_PAYPAL_PAYMENT_STATUS_DENI type COM_WEC_PAYPAL_PAYMENT_STATUS value `Denied`. "#EC NOTEXT . class-data GC_PAYPAL_PAYMENT_STATUS_NONE type COM_WEC_PAYPAL_PAYMENT_STATUS value `None`. "#EC NOTEXT . class-data GC_PAYPAL_PAYMENT_STATUS_PEND type COM_WEC_PAYPAL_PAYMENT_STATUS value `Pending`. "#EC NOTEXT . class-data GC_PAYPAL_PAYMENT_STATUS_REFU type COM_WEC_PAYPAL_PAYMENT_STATUS value `Refunded`. "#EC NOTEXT . class-data GC_TXN_PROFILE type COM_WEC_TRANSACTION_PROFILE value 'PF01'. "#EC NOTEXT . class-data GC_TXN_STATUS_COMP type COM_WEC_TRANSACTION_STATUS value 'COMP'. "#EC NOTEXT . class-data GC_TXN_STATUS_PEND type COM_WEC_TRANSACTION_STATUS value 'PEND'. "#EC NOTEXT . class-data GC_TXN_STATUS_REJE type COM_WEC_TRANSACTION_STATUS value 'REJE'. "#EC NOTEXT . data GC_TXN_STATUS_RFND type COM_WEC_TRANSACTION_STATUS value 'RFND'. "#EC NOTEXT . data MV_USERNAME type STRING . data MV_PASSWORD type STRING . October 2013 237 Development and Extension Guide – Application-Specific Information data MV_TOKEN type COM_WEC_PAYPAL_TOKEN . class-data GC_PROCESS_STATUS_CONFIRMED type STRING value 'confirmed'. "#EC NOTEXT . type-pools ABAP . methods SEARCH_TRANSACTION_BY_REF_ID importing !IV_REFERENCE_ID type COM_WEC_TRANSACTION_ID exporting !EV_ERROR_OCCURRED type ABAP_BOOL !EV_TRANSACTION_EXISTS type ABAP_BOOL !EV_PAYPAL_TRANSACTION_ID type COM_WEC_PAYPAL_TRANSACTION_ID changing !CT_MESSAGES type COMT_WEC_MESSAGES !CT_SYSLOG_MESSAGES type COMT_WEC_MESSAGES . class-methods ADD_MESSAGE importing !IV_TYPE type BAPI_MTYPE !IV_ID type SYMSGID default GC_MESSAGE_ID !IV_NUMBER type SYMSGNO !IV_MESSAGE_V1 type SIMPLE optional !IV_MESSAGE_V2 type SIMPLE optional !IV_MESSAGE_V3 type SIMPLE optional !IV_MESSAGE_V4 type SIMPLE optional changing !CT_MESSAGES type COMT_WEC_MESSAGES optional . class-methods GET_PAYER_ID importing !IT_PARAMETERS type COMT_WEC_HTTP_PARAMETERS !IT_NAME_VALUE type COMT_WEC_PSP_NAME_VALUE_PAIR returning value(RV_PAYER_ID) type COM_WEC_PAYPAL_PAYER_ID . class-methods GET_SHIPTO_ADDRESS importing !IS_SHIPPING_ADDRESS type ANY returning value(RS_SHIPTO_ADDRESS) type COMS_WEC_PAYPAL_SHIPTO_ADDRESS . methods IS_TOKEN_VALID importing !IT_PARAMETERS type COMT_WEC_HTTP_PARAMETERS !IT_NAME_VALUE type COMT_WEC_PSP_NAME_VALUE_PAIR returning value(RV_TOKEN_VALID) type ABAP_BOOL . class-methods IS_TRANSACTION_CONFIRMED importing !IT_PARAMETERS type COMT_WEC_HTTP_PARAMETERS !IT_NAME_VALUE type COMT_WEC_PSP_NAME_VALUE_PAIR returning value(RV_TRANSACTION_CONFIRMED) type COM_WEC_PAYPAL_PAYER_ID . class-methods ADD_API_MESSAGES importing !IT_API_MESSAGES type BAPIRET2_TAB changing !CT_MESSAGES type COMT_WEC_MESSAGES . 238 October 2013 Development and Extension Guide – Application-Specific Information class-methods COUNTRY_SAP2PP importing !IV_COUNTRY type LAND1 returning value(RV_COUNTRY) type STRING . class-methods REGION_SAP2PP importing !IV_REGIO type REGIO !IV_COUNTRY type LAND1 returning value(RV_REGIO_PP) type STRING . class-methods GET_DEFAULT_USERNAME returning value(RV_USERNAME) type STRING . class-methods GET_DEFAULT_PASSWORD returning value(RV_PASSWORD) type STRING . ENDCLASS. CLASS ZCL_ERP_PAYPAL_IMPL IMPLEMENTATION. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_ERP_PAYPAL_IMPL->ADD_API_MESSAGES * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> method ADD_API_MESSAGES. * Add API messages to message table DATA ls_message LIKE LINE OF ct_messages. FIELD-SYMBOLS <ls_api_message> LIKE LINE OF it_api_messages. LOOP AT it_api_messages ASSIGNING <ls_api_message>. CLEAR ls_message. MOVE-CORRESPONDING <ls_api_message> TO ls_message. INSERT ls_message INTO TABLE ct_messages. ENDLOOP. endmethod. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_ERP_PAYPAL_IMPL->ADD_MESSAGE * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> method ADD_MESSAGE. * Add a message to table CT_MESSAGES October 2013 239 Development and Extension Guide – Application-Specific Information DATA ls_message LIKE LINE OF ct_messages. ls_message-type = iv_type. ls_message-id = iv_id. ls_message-number = iv_number. ls_message-message_v1 = iv_message_v1. ls_message-message_v2 = iv_message_v2. ls_message-message_v3 = iv_message_v3. ls_message-message_v4 = iv_message_v4. MESSAGE ID iv_id TYPE iv_type NUMBER iv_number WITH iv_message_v1 iv_message_v2 iv_message_v3 iv_message_v4 INTO ls_message-message. INSERT ls_message INTO TABLE ct_messages. endmethod. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_ERP_PAYPAL_IMPL->CONSTRUCTOR * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_ERP_PAYPAL_IMPL->COUNTRY_SAP2PP * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> method COUNTRY_SAP2PP. DATA lv_country_iso TYPE INTCA. CALL FUNCTION 'COUNTRY_CODE_SAP_TO_ISO' EXPORTING sap_code = iv_country IMPORTING ISO_CODE = lv_country_iso EXCEPTIONS NOT_FOUND = 1 OTHERS = 2 . IF sy-subrc <> 0. rv_country = iv_country. ELSE. rv_country = lv_country_iso. ENDIF. endmethod. 240 October 2013 Development and Extension Guide – Application-Specific Information * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_ERP_PAYPAL_IMPL->GET_DEFAULT_PASSWORD * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> method GET_DEFAULT_PASSWORD. * detmermine the default password endmethod. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_ERP_PAYPAL_IMPL->GET_DEFAULT_USERNAME * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> method GET_DEFAULT_USERNAME. * determine the default username endmethod. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_ERP_PAYPAL_IMPL->GET_PAYER_ID * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> method GET_PAYER_ID. * Get the payer ID of the PayPal customer; this is passed in by PayPal in the * redirect to the Web Channel FIELD-SYMBOLS <ls_parameter> TYPE coms_wec_http_parameter. FIELD-SYMBOLS <lv_payer_id> TYPE string. FIELD-SYMBOLS <fs_name_value> TYPE coms_wec_psp_name_value_pair. DATA dref TYPE REF TO coms_wec_http_parameter. DATA lv_subrc TYPE sysubrc. CLEAR rv_payer_id. * Get the payer ID from the HTTP parameters passed in by PayPal READ TABLE it_parameters ASSIGNING <ls_parameter> WITH TABLE KEY name = `PayerID`. lv_subrc = sy-subrc. IF lv_subrc NE 0. CREATE DATA dref. ASSIGN dref->* TO <ls_parameter>. READ TABLE it_name_value ASSIGNING <fs_name_value> WITH KEY name = `payerID`. lv_subrc = sy-subrc. IF lv_subrc EQ 0. <ls_parameter>-name = <fs_name_value>-name. October 2013 241 Development and Extension Guide – Application-Specific Information INSERT <fs_name_value>-value INTO TABLE <ls_parameter>-values. ENDIF. ENDIF. * We expect exactly one value for the payer id IF sy-subrc = 0 AND lines( <ls_parameter>-values ) = 1. READ TABLE <ls_parameter>-values ASSIGNING <lv_payer_id> INDEX 1. IF sy-subrc = 0. rv_payer_id = <lv_payer_id>. ENDIF. ENDIF. endmethod. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_ERP_PAYPAL_IMPL->GET_SHIPTO_ADDRESS * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> method GET_SHIPTO_ADDRESS. DATA ls_shipping_address TYPE lty_psp_shippig_address. DATA lv_name_string TYPE string. * Convert the internal shipping address to the PayPal shipto address MOVE-CORRESPONDING is_shipping_address TO ls_shipping_address. IF ls_shipping_address-name1 IS NOT INITIAL. lv_name_string = ls_shipping_address-name1. ENDIF. IF ls_shipping_address-name2 IS NOT INITIAL. lv_name_string = lv_name_string && ` ` && ls_shipping_address-name2. ENDIF. IF ls_shipping_address-name3 IS NOT INITIAL. lv_name_string = lv_name_string && ` ` && ls_shipping_address-name3. ENDIF. IF ls_shipping_address-name4 IS NOT INITIAL. lv_name_string = lv_name_string && ` ` && ls_shipping_address-name4. ENDIF. IF lv_name_string IS INITIAL. lv_name_string = ls_shipping_address-name_first. IF ls_shipping_address-namemiddle IS NOT INITIAL. lv_name_string = lv_name_string && ` ` && ls_shipping_address-namemiddle. ENDIF. IF ls_shipping_address-name_last IS NOT INITIAL. lv_name_string = lv_name_string && ` ` && ls_shipping_address-name_last. ENDIF. IF ls_shipping_address-name_last2 IS NOT INITIAL. lv_name_string = lv_name_string && ` ` && ls_shipping_address-name_last2. ENDIF. 242 October 2013 Development and Extension Guide – Application-Specific Information ENDIF. CLEAR rs_shipto_address. rs_shipto_address-name = lv_name_string. rs_shipto_address-street1 = ls_shipping_address-street. rs_shipto_ADDRESS-STREET2 = ls_shipping_address-str_suppl1. rs_shipto_address-city_name = ls_shipping_address-city1. rs_shipto_address-state_or_province = region_sap2pp( iv_regio = ls_shipping_address-region iv_country = ls_shipping_address-country ). rs_shipto_address-country = country_sap2pp( iv_country = ls_shipping_address-country ). rs_shipto_address-postal_code = ls_shipping_address-post_code1. endmethod. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Public Method ZCL_ERP_PAYPAL_IMPL->IF_COM_WEC_PSP_INTEGRATION~CANCEL_TRANSACTION * +--------------------------------------------------------------------------------------------- ----+ * | [--->] IS_REFERENCE_DOCUMENT TYPE COMS_WEC_BUSINESS_OBJECT * | [--->] IV_REFERENCE_GUID TYPE COM_WEC_TRANSACTION_GUID * | [--->] IV_REFERENCE_ID TYPE COM_WEC_TRANSACTION_ID * | [--->] IV_PSP_TRANSACTION_ID TYPE COM_WEC_PSP_TRANSACTION_ID * | [<---] ER_ACTION TYPE REF TO CL_COM_WEC_CANCEL_TRANS_PARAM * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD if_com_wec_psp_integration~cancel_transaction. * Refund a PayPal transaction after cancelling the corresponding order DATA lv_paypal_original_trans_id TYPE com_wec_paypal_transaction_id. DATA lv_paypal_refund_trans_id TYPE com_wec_paypal_transaction_id. DATA lv_psp_refund_trans_id TYPE com_wec_psp_transaction_id. DATA lt_api_messages TYPE bapiret2_tab. DATA lv_api_success TYPE abap_bool. DATA lt_messages TYPE comt_wec_messages. DATA lt_syslog_messages TYPE comt_wec_messages. ************************************************************************ * Call Sandbox " Call Sandbox System " Convert the original transaction ID of the payment to be refunded lv_paypal_original_trans_id = iv_psp_transaction_id. " Call the PayPal refund API ZCL_COMMON_PAYPAL_API=>refund_transaction( EXPORTING iv_username = get_default_username( ) iv_password = get_default_password( ) iv_signature = gc_signature iv_logical_port = gc_logical_port October 2013 243 Development and Extension Guide – Application-Specific Information iv_transaction_id = lv_paypal_original_trans_id iv_refund_type = ZCL_COMMON_PAYPAL_API=>gc_refund_type_full IMPORTING ev_refund_trans_id = lv_paypal_refund_trans_id et_messages = lt_api_messages ev_success = lv_api_success ). * If refund successfull, finalize the cancellation IF lv_api_success = abap_true. * Convert the refund transaction ID to the internal format lv_psp_refund_trans_id = lv_paypal_refund_trans_id. CREATE OBJECT er_action TYPE cl_com_wec_finalize_cancel EXPORTING iv_transaction_status_profile = 'PF01' iv_transaction_status = 'RFND'. * If an error occured, schedule for later reprocessing ELSE. add_message( EXPORTING iv_type = 'E' iv_number = 000 iv_message_v1 = 'RefundTransaction' CHANGING ct_messages = lt_messages ). add_message( EXPORTING iv_type = 'E' iv_number = 000 iv_message_v1 = 'RefundTransaction' CHANGING ct_messages = lt_syslog_messages ). add_api_messages( EXPORTING it_api_messages = lt_api_messages CHANGING ct_messages = lt_syslog_messages ). CREATE OBJECT er_action TYPE cl_com_wec_reprocess_cancel EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. ENDIF. ENDMETHOD. 244 October 2013 Development and Extension Guide – Application-Specific Information * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Public Method ZCL_ERP_PAYPAL_IMPL- >IF_COM_WEC_PSP_INTEGRATION~GET_TRANSACTION_DETAILS * +--------------------------------------------------------------------------------------------- ----+ * | [--->] IS_REFERENCE_DOCUMENT TYPE COMS_WEC_BUSINESS_OBJECT * | [--->] IV_REFERENCE_GUID TYPE COM_WEC_TRANSACTION_GUID * | [--->] IV_REFERENCE_ID TYPE COM_WEC_TRANSACTION_ID * | [--->] IV_PSP_TRANSACTION_ID TYPE COM_WEC_PSP_TRANSACTION_ID * | [<---] ER_ACTION TYPE REF TO CL_COM_WEC_UPDATE_TRANS_PARAM * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD if_com_wec_psp_integration~get_transaction_details. * Get PayPal transaction details for an order DATA lv_psp_transaction_id TYPE com_wec_psp_transaction_id. DATA lt_api_messages TYPE bapiret2_tab. DATA lv_api_success TYPE abap_bool. DATA lt_messages TYPE comt_wec_messages. DATA lt_syslog_messages TYPE comt_wec_messages. DATA: lv_vbeln TYPE vbeln, ls_vbak TYPE vbak, lr_paysp TYPE REF TO cl_sls_paysp_integration, ls_paysp_hl TYPE paysp_hl. * Call Sandbox * If the PSP transaction ID is given, we assume it is valid and use it to get the transaction details DATA lv_error_occurred_in_search TYPE abap_bool. DATA lv_transaction_exists TYPE abap_bool. DATA lv_paypal_transaction_id TYPE com_wec_paypal_transaction_id. DATA lv_paypal_payment_status TYPE com_wec_paypal_payment_status. IF iv_psp_transaction_id IS NOT INITIAL. lv_paypal_transaction_id = iv_psp_transaction_id. * If the refernce ID is given, use it to check if the transaction exists in the PayPal system ELSEIF iv_reference_id IS NOT INITIAL. search_transaction_by_ref_id( EXPORTING iv_reference_id = iv_reference_id IMPORTING ev_error_occurred = lv_error_occurred_in_search ev_transaction_exists = lv_transaction_exists ev_paypal_transaction_id = lv_paypal_transaction_id CHANGING ct_messages = lt_messages ct_syslog_messages = lt_syslog_messages ). * If search failed, reprocess the order later October 2013 245 Development and Extension Guide – Application-Specific Information IF lv_error_occurred_in_search = abap_true. CREATE OBJECT er_action TYPE cl_com_wec_reprocess_update EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. RETURN. ENDIF. * If transaction is not known in the PayPal system, cancel the order IF lv_transaction_exists = abap_false. CREATE OBJECT er_action TYPE cl_com_wec_invalidate_trans EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. RETURN. ENDIF. * Neither PSP transaction ID or reference ID supplied. Give up because a search by transaction GUID * is not supported by PayPal so there is no other option to find the transaction. ELSE. add_message( EXPORTING iv_type = 'E' iv_number = 007 iv_message_v1 = 'GET_TRANSACTION_DETAILS' CHANGING ct_messages = lt_messages ). add_message( EXPORTING iv_type = 'E' iv_number = 007 iv_message_v1 = 'GET_TRANSACTION_DETAILS' CHANGING ct_messages = lt_syslog_messages ). CREATE OBJECT er_action TYPE cl_com_wec_reprocess_update EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. RETURN. ENDIF. * Get transaction details from PayPal ZCL_COMMON_PAYPAL_API=>get_transaction_details( EXPORTING iv_username = get_default_username( ) 246 October 2013 Development and Extension Guide – Application-Specific Information iv_password = get_default_password( ) iv_signature = gc_signature iv_logical_port = gc_logical_port iv_transaction_id = lv_paypal_transaction_id IMPORTING ev_payment_status = lv_paypal_payment_status et_messages = lt_api_messages ev_success = lv_api_success ). * Put API messages in the application log add_api_messages( EXPORTING it_api_messages = lt_api_messages CHANGING ct_messages = lt_syslog_messages ). ************************************************************************ * PayPal API call successfull -> process PayPal payment status IF lv_api_success = abap_true. lv_psp_transaction_id = lv_paypal_transaction_id. CASE lv_paypal_payment_status. * PayPal has no payment status -> cancel corresponding order WHEN gc_paypal_payment_status_none. CREATE OBJECT er_action TYPE cl_com_wec_invalidate_trans EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. * PayPal transaction has status completed -> set PSP status accordingly WHEN gc_paypal_payment_status_comp. CREATE OBJECT er_action TYPE cl_com_wec_update_transaction EXPORTING iv_transaction_status_profile = 'PF01' iv_transaction_status = 'COMP' iv_psp_transaction_id = lv_psp_transaction_id it_messages = lt_messages it_syslog_messages = lt_syslog_messages. * PayPal transaction has status pending -> set PSP status accordingly WHEN gc_paypal_payment_status_pend. CREATE OBJECT er_action TYPE cl_com_wec_update_transaction EXPORTING iv_transaction_status_profile = 'PF01' iv_transaction_status = 'PEND' iv_psp_transaction_id = lv_psp_transaction_id it_messages = lt_messages it_syslog_messages = lt_syslog_messages. * PayPal transaction has status refunded -> set PSP status accordingly October 2013 247 Development and Extension Guide – Application-Specific Information WHEN gc_paypal_payment_status_refu. CREATE OBJECT er_action TYPE cl_com_wec_update_transaction EXPORTING iv_transaction_status_profile = 'PF01' iv_transaction_status = 'RFND' iv_psp_transaction_id = lv_psp_transaction_id it_messages = lt_messages it_syslog_messages = lt_syslog_messages. * PayPal transaction has status denied -> set PSP status to rejected WHEN gc_paypal_payment_status_deni. CREATE OBJECT er_action TYPE cl_com_wec_update_transaction EXPORTING iv_transaction_status_profile = 'PF01' iv_transaction_status = 'REJE' iv_psp_transaction_id = lv_psp_transaction_id it_messages = lt_messages it_syslog_messages = lt_syslog_messages. * PayPal returned an unexpected status -> raise an error and reprocess later WHEN OTHERS. add_message( EXPORTING iv_type = 'E' iv_number = 004 iv_message_v1 = 'GetTransactionDetails' iv_message_v2 = lv_paypal_payment_status CHANGING ct_messages = lt_messages ). add_message( EXPORTING iv_type = 'E' iv_number = 004 iv_message_v1 = 'GetTransactionDetails' iv_message_v2 = lv_paypal_payment_status CHANGING ct_messages = lt_syslog_messages ). CREATE OBJECT er_action TYPE cl_com_wec_reprocess_update EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. ENDCASE. * If an error occured, schedule for later reprocessing ELSE. add_message( EXPORTING iv_type = 'E' 248 October 2013 Development and Extension Guide – Application-Specific Information iv_number = 000 iv_message_v1 = 'GetTransactionDetails' CHANGING ct_messages = lt_messages ). add_message( EXPORTING iv_type = 'E' iv_number = 000 iv_message_v1 = 'GetTransactionDetails' CHANGING ct_messages = lt_syslog_messages ). CREATE OBJECT er_action TYPE cl_com_wec_reprocess_update EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. ENDIF. ENDMETHOD. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Public Method ZCL_ERP_PAYPAL_IMPL->IF_COM_WEC_PSP_INTEGRATION~INITIATE_TRANSACTION * +--------------------------------------------------------------------------------------------- ----+ * | [--->] IS_REFERENCE_DOCUMENT TYPE COMS_WEC_BUSINESS_OBJECT * | [--->] IV_TRANSACTION_AMOUNT TYPE COM_WEC_TRANSACTION_AMOUNT * | [--->] IV_TRANSACTION_CURRENCY TYPE COM_WEC_TRANSACTION_CURRENCY * | [--->] IS_SHIPPING_ADDRESS TYPE COMS_WEC_PAYMENT_ADDR * | [--->] IV_REFERENCE_GUID TYPE COM_WEC_TRANSACTION_GUID * | [--->] IV_REFERENCE_ID TYPE COM_WEC_TRANSACTION_ID * | [--->] IV_WEC_SOURCE_URL TYPE STRING * | [--->] IT_NAME_VALUE TYPE COMT_WEC_PSP_NAME_VALUE_PAIR * | [<---] ER_ACTION TYPE REF TO CL_COM_WEC_CREATE_TRANS_PARAM * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD if_com_wec_psp_integration~initiate_transaction. * Initiate a PayPal transaction (call the PayPal web service DoExpressCheckoutPayment * and redirect the user to the PayPal web site) DATA lv_return_url TYPE string. DATA lv_cancel_url TYPE string. DATA lv_invoice_id TYPE com_wec_paypal_invoice_id. DATA lv_custom TYPE com_wec_paypal_custom. DATA lv_target_url TYPE string. DATA lv_api_success TYPE abap_bool. DATA lt_api_messages TYPE bapiret2_tab. DATA lt_messages TYPE comt_wec_messages. DATA lt_syslog_messages TYPE comt_wec_messages. * Build the return and cancel URLs October 2013 249 Development and Extension Guide – Application-Specific Information lv_return_url = iv_wec_source_url && `sap-wec-pp-status=` && gc_process_status_confirmed. lv_cancel_url = iv_wec_source_url && `sap-wec-pp-status=cancelled`. * Fill invoice ID (order number) and custom field (transaction GUID) lv_invoice_id = iv_reference_id. lv_custom = iv_reference_guid. * Call the PayPal API ZCL_COMMON_PAYPAL_API=>set_express_checkout( EXPORTING iv_username = get_default_username( ) iv_password = get_default_password( ) iv_signature = gc_signature iv_logical_port = gc_logical_port iv_amount = iv_transaction_amount iv_currency = iv_transaction_currency iv_return_url = lv_return_url iv_cancel_url = lv_cancel_url iv_invoice_id = lv_invoice_id iv_custom = lv_custom IMPORTING ev_token = mv_token et_messages = lt_api_messages ev_success = lv_api_success ). * If an error occured in the API call, output messages and return to checkout page IF lv_api_success = abap_false. add_message( EXPORTING iv_type = 'E' iv_number = 000 iv_message_v1 = 'doExpressCheckout' CHANGING ct_messages = lt_messages ). lt_syslog_messages = lt_messages. add_api_messages( EXPORTING it_api_messages = lt_api_messages CHANGING ct_messages = lt_syslog_messages ). CREATE OBJECT er_action TYPE cl_com_wec_initiate_trans EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. * If the token is initial, ouptut messages and return to checkout page ELSEIF mv_token IS INITIAL. add_message( EXPORTING 250 October 2013 Development and Extension Guide – Application-Specific Information iv_type = 'E' iv_number = 001 iv_message_v1 = 'doExpressCheckout' CHANGING ct_messages = lt_messages ). lt_syslog_messages = lt_messages. add_api_messages( EXPORTING it_api_messages = lt_api_messages CHANGING ct_messages = lt_syslog_messages ). CREATE OBJECT er_action TYPE cl_com_wec_initiate_trans EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. * If no error occured, redirect to PayPal ELSE. lv_target_url = `https://www.sandbox.paypal.com/webscr&cmd=_express-checkout&token=` && mv_token. CREATE OBJECT er_action TYPE cl_com_wec_trigger_redirect EXPORTING iv_target_url = lv_target_url it_syslog_messages = lt_syslog_messages. ENDIF. ENDMETHOD. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Public Method ZCL_ERP_PAYPAL_IMPL->IF_COM_WEC_PSP_INTEGRATION~PROCESS_CALLBACK * +--------------------------------------------------------------------------------------------- ----+ * | [--->] IS_REFERENCE_DOCUMENT TYPE COMS_WEC_BUSINESS_OBJECT * | [--->] IV_TRANSACTION_AMOUNT TYPE COM_WEC_TRANSACTION_AMOUNT * | [--->] IV_TRANSACTION_CURRENCY TYPE COM_WEC_TRANSACTION_CURRENCY * | [--->] IS_SHIPPING_ADDRESS TYPE COMS_WEC_PAYMENT_ADDR * | [--->] IV_REFERENCE_GUID TYPE COM_WEC_TRANSACTION_GUID * | [--->] IV_REFERENCE_ID TYPE COM_WEC_TRANSACTION_ID * | [--->] IV_WEC_TARGET_URL TYPE STRING * | [--->] IT_PARAMETERS TYPE COMT_WEC_HTTP_PARAMETERS * | [--->] IT_NAME_VALUE TYPE COMT_WEC_PSP_NAME_VALUE_PAIR * | [<---] ER_ACTION TYPE REF TO CL_COM_WEC_CREATE_TRANS_PARAM * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD if_com_wec_psp_integration~process_callback. * Process the redirection from PayPal to the Web Channel DATA lv_paypal_transaction_id TYPE com_wec_paypal_transaction_id. October 2013 251 Development and Extension Guide – Application-Specific Information DATA lv_paypal_payment_status TYPE com_wec_paypal_payment_status. DATA lv_psp_transaction_id TYPE com_wec_psp_transaction_id. DATA lv_api_success TYPE abap_bool. DATA lt_api_messages TYPE bapiret2_tab. DATA lt_messages TYPE comt_wec_messages. DATA lt_syslog_messages TYPE comt_wec_messages. * If the transaction is not confirmed, redirect the user to the checkout page IF is_transaction_confirmed( it_parameters = it_parameters it_name_value = it_name_value ) = abap_false. add_message( EXPORTING iv_type = 'I' iv_number = 002 CHANGING ct_messages = lt_messages ). lt_syslog_messages = lt_messages. CREATE OBJECT er_action TYPE cl_com_wec_initiate_trans EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. RETURN. ENDIF. * If the token returned by PayPal is invalid, redirect the user to the checkout page IF is_token_valid( it_parameters = it_parameters it_name_value = it_name_value ) = abap_false. add_message( EXPORTING iv_type = 'E' iv_number = 003 CHANGING ct_messages = lt_messages ). lt_syslog_messages = lt_messages. CREATE OBJECT er_action TYPE cl_com_wec_initiate_trans EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. RETURN. ENDIF. * Call the PayPal API ZCL_COMMON_PAYPAL_API=>do_express_checkout_payment( EXPORTING iv_username = get_default_username( ) iv_password = get_default_password( ) iv_signature = gc_signature 252 October 2013 Development and Extension Guide – Application-Specific Information iv_logical_port =gc_logical_port iv_amount =iv_transaction_amount iv_currency =iv_transaction_currency iv_token =mv_token iv_payerid =get_payer_id( it_parameters = it_parameters it_name_value = it_name_value ) is_shipto_address = get_shipto_address( is_shipping_address ) IMPORTING ev_transaction_id = lv_paypal_transaction_id ev_payment_status = lv_paypal_payment_status et_messages = lt_api_messages ev_success = lv_api_success ). * If an error occured in the API call, return the user to the checkout page IF lv_api_success = abap_false. add_message( EXPORTING iv_type = 'E' iv_number = 000 iv_message_v1 = 'doExpressCheckoutPayment' CHANGING ct_messages = lt_messages ). lt_syslog_messages = lt_messages. CREATE OBJECT er_action TYPE cl_com_wec_initiate_trans EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. RETURN. ENDIF. * Convert PayPal transaction ID to SAP internal transaction ID lv_psp_transaction_id = lv_paypal_transaction_id. * Check the payment status and finalize the transaction or start over with the checkout CASE lv_paypal_payment_status. WHEN gc_paypal_payment_status_comp. CREATE OBJECT er_action TYPE cl_com_wec_finalize_trans EXPORTING iv_transaction_status_profile = gc_txn_profile iv_transaction_status = gc_txn_status_comp iv_psp_transaction_id = lv_psp_transaction_id. WHEN gc_paypal_payment_status_pend. CREATE OBJECT er_action TYPE cl_com_wec_finalize_trans EXPORTING iv_transaction_status_profile = gc_txn_profile iv_transaction_status = gc_txn_status_pend October 2013 253 Development and Extension Guide – Application-Specific Information iv_psp_transaction_id = lv_psp_transaction_id. WHEN OTHERS. add_message( EXPORTING iv_type = 'E' iv_number = 000 iv_message_v1 = 'doExpressCheckoutPayment' iv_message_v2 = lv_paypal_payment_status CHANGING ct_messages = lt_messages ). lt_syslog_messages = lt_messages. CREATE OBJECT er_action TYPE cl_com_wec_initiate_trans EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. ENDCASE. ENDMETHOD. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_ERP_PAYPAL_IMPL->IS_TOKEN_VALID * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD is_token_valid. * Check if the token returned by PayPal after the redirect to the Web Channel * is the same as supplied by the web service SetExpressCheckout FIELD-SYMBOLS <ls_parameter> TYPE coms_wec_http_parameter. FIELD-SYMBOLS <lv_token> TYPE string. FIELD-SYMBOLS <fs_name_value> TYPE coms_wec_psp_name_value_pair. DATA dref TYPE REF TO coms_wec_http_parameter. DATA lv_subrc TYPE sysubrc. rv_token_valid = abap_false. * Read the URL parameter READ TABLE it_parameters ASSIGNING <ls_parameter> WITH TABLE KEY name = `token`. lv_subrc = sy-subrc. IF lv_subrc NE 0. CREATE DATA dref. ASSIGN dref->* TO <ls_parameter>. READ TABLE it_name_value ASSIGNING <fs_name_value> WITH KEY name = `token`. lv_subrc = sy-subrc. IF lv_subrc EQ 0. 254 October 2013 Development and Extension Guide – Application-Specific Information <ls_parameter>-name = <fs_name_value>-name. INSERT <fs_name_value>-value INTO TABLE <ls_parameter>-values. ENDIF. ENDIF. * We expect exactly one value for the token IF lv_subrc = 0 AND lines( <ls_parameter>-values ) = 1. READ TABLE <ls_parameter>-values ASSIGNING <lv_token> INDEX 1. IF sy-subrc = 0 AND mv_token = <lv_token>. rv_token_valid = abap_true. ENDIF. ENDIF. ENDMETHOD. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_ERP_PAYPAL_IMPL->IS_TRANSACTION_CONFIRMED * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD is_transaction_confirmed. * Check if the payment transaction was confirmed by the payer FIELD-SYMBOLS <ls_parameter> TYPE coms_wec_http_parameter. FIELD-SYMBOLS <lv_status> TYPE string. FIELD-SYMBOLS <fs_name_value> TYPE coms_wec_psp_name_value_pair. DATA dref TYPE REF TO coms_wec_http_parameter. DATA lv_subrc TYPE sysubrc. rv_transaction_confirmed = abap_false. * Get the URL parameter from the HTTP parameters passed in by PayPal READ TABLE it_parameters ASSIGNING <ls_parameter> WITH TABLE KEY name = `sap-wec-pp-status`. lv_subrc = sy-subrc. * We expect exactly one value for the parameter IF lv_subrc = 0 AND lines( <ls_parameter>-values ) = 1. READ TABLE <ls_parameter>-values ASSIGNING <lv_status> INDEX 1. IF sy-subrc = 0 AND <lv_status> = gc_process_status_confirmed. rv_transaction_confirmed = abap_true. ENDIF. ENDIF. ENDMETHOD. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_ERP_PAYPAL_IMPL->REGION_SAP2PP * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> method REGION_SAP2PP. October 2013 255 Development and Extension Guide – Application-Specific Information * region codes of paypal for canada differ from sap region codes(table T005S). * Map the ones that are differing. CASE iv_country. WHEN 'CA'. CASE iv_regio. WHEN 'NL'. rv_regio_pp = 'NF'. WHEN 'YT'. rv_regio_pp = 'YK'. WHEN OTHERS. rv_regio_pp = iv_regio. ENDCASE. WHEN OTHERS. rv_regio_pp = iv_regio. ENDCASE. endmethod. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_ERP_PAYPAL_IMPL->SEARCH_TRANSACTION_BY_REF_ID * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD search_transaction_by_ref_id. * Search for a PayPal transaction by our reference ID (= PayPal invoice ID). Note * that searching by our transaction GUID is currently not supported by PayPal's web * services. * Possible return values: * EV_ERROR_OCCURRED = ABAP_FALSE and EV_TRANSACTION_EXISTS = ABAP_TRUE * -> Transaction does exist in the PayPal system. Transaction ID returned in EV_PAYPAL_TRANSACTION_ID * * EV_ERROR_OCCURRED = ABAP_FALSE and EV_TRANSACTION_EXISTS = ABAP_FALSE * -> Transaction does not exist in the PayPal system. * * EV_ERROR_OCCURRED = ABAP_TRUE * -> An error occured when searching in the PayPal system; cannot tell if transactoin * exists or not. * -> More than one transaction found (should never occur) DATA lv_paypal_invoice_id TYPE com_wec_paypal_invoice_id. DATA lv_start_date TYPE timestamp. DATA lt_paypal_transaction_ids TYPE comt_wec_paypal_transaction_id. DATA lt_api_messages TYPE bapiret2_tab. DATA lv_api_success TYPE abap_bool. ev_error_occurred = abap_true. ev_transaction_exists = abap_false. CLEAR ev_paypal_transaction_id. * Convert SAP reference ID to PayPal's invoice ID 256 October 2013 Development and Extension Guide – Application-Specific Information lv_paypal_invoice_id = iv_reference_id. * Set start date for search CONVERT DATE '19000101' TIME '000000' INTO TIME STAMP lv_start_date TIME ZONE 'UTC '. * Execute the search ZCL_COMMON_PAYPAL_API=>transaction_search( EXPORTING iv_username = mv_username iv_password = mv_password iv_signature = gc_signature iv_logical_port = gc_logical_port iv_invoice_id = lv_paypal_invoice_id iv_start_date = lv_start_date IMPORTING et_transaction_ids = lt_paypal_transaction_ids et_messages = lt_api_messages ev_success = lv_api_success ). * Put API messages in the application log add_api_messages( EXPORTING it_api_messages = lt_api_messages CHANGING ct_messages = ct_syslog_messages ). * API call not successfull -> add error and return IF lv_api_success = abap_false. add_message( EXPORTING iv_type = 'E' iv_number = 005 iv_message_v1 = iv_reference_id CHANGING ct_messages = ct_messages ). add_message( EXPORTING iv_type = 'E' iv_number = 005 iv_message_v1 = iv_reference_id CHANGING ct_messages = ct_syslog_messages ). RETURN. ENDIF. * More than one transaction found for the reference number; this indicates a potential * error in the SAP system -> add error and return IF lines( lt_paypal_transaction_ids ) > 1. add_message( EXPORTING iv_type = 'E' iv_number = 006 iv_message_v1 = iv_reference_id October 2013 257 Development and Extension Guide – Application-Specific Information CHANGING ct_messages = ct_messages ). add_message( EXPORTING iv_type = 'E' iv_number = 006 iv_message_v1 = iv_reference_id CHANGING ct_messages = ct_syslog_messages ). RETURN. ENDIF. * If we got here, the API call was successful and returned no transaction ID * (transaction not known in the PayPal system) or one transaction ID (transaction * known in the PayPal system) ev_error_occurred = abap_false. * Read transaction ID if any READ TABLE lt_paypal_transaction_ids INTO ev_paypal_transaction_id INDEX 1. IF sy-subrc = 0 AND ev_paypal_transaction_id IS NOT INITIAL. ev_transaction_exists = abap_true. ENDIF. ENDMETHOD. ENDCLASS. 258 October 2013 Development and Extension Guide – Application-Specific Information 6.1.4 SAP CRM Replication Scenario In the SAP CRM replication scenario, order management is completed in the SAP CRM back end. Order fulfillment, billing, and financials are completed in the SAP ERP back end. The following figure shows the SAP CRM replication scenario: In the SAP CRM replication scenario, some configuration and the implementation of BAdI Integrating Payment Service Providers must be completed in the SAP CRM back end. Some configuration and the BAdI Import Settlement Files for Each Payment Service Provider must be implemented in the SAP ERP back end. The sales order in the SAP CRM back end gets status information from the payment service provider using the payment service provider interface (PSP IF). The sales order in the SAP CRM back end, including its payment service provider status information, is replicated to the sales order in the SAP ERP back end. The sales order in SAP ERP passes the payment service provider information by way of billing to financials for settlement. October 2013 259 Development and Extension Guide – Application-Specific Information Consider the activities in the following sections when using the SAP CRM replication scenario. 1. Activate business function in the SAP ERP back end. Activate the ERP_WEB_CHANNEL_1 business function. 2. Maintain Customizing for payment service provider integration in the SAP ERP back end. Make the settings in Customizing for SAP ERP under Sales and Distribution -> SAP Web Channel Experience Management -> Payment Service Prov. 3. Activate business function in the SAP CRM back end. Activate the CRM_WEB_CHANNEL business function. 4. Maintain Customizing for payment service provider integration in the SAP CRM back end. Make the settings in Customizing for SAP CRM under Customer Relationship Management -> SAP Web Channel Experience Management -> E-Commerce -> Payment Service Providers. 5. Implement BAdI: Integration of Payment Service Providers in the SAP CRM back end. Implement all relevant proxy calls to the Web services provided by the payment service provider (see subsection Call to the Proxy in section Creating Web Service Wrapper). For more information, see Sample Implementation of BAdI 'Integration of Payment Service Providers' in the SAP CRM Back End. 6. Schedule periodic tasks in the SAP CRM back end. Use the program Process Incomplete Payment Service Provider Orders (transaction CRMD_WEC_PSP_ORDER) to identify and process incomplete sales orders and service orders in the SAP CRM back end that Web shop customers create using payment service providers. For more information, see the online documentation for the program. 260 October 2013 Development and Extension Guide – Application-Specific Information 6.1.4.1 Sample Implementation of BAdI 'Integration of Payment Service Providers' in the SAP CRM Back End The following code is a sample implementation. In this sample implementation, the Web service calls are encapsulated in class ZCL_COMMON_PAYPAL_API. Sample BAdI implementation ZCL_CRM_PAYPAL_IMPL: class ZCL_CRM_PAYPAL_IMPL definition public final create public . public section. *"* public components of class ZCL_CRM_PAYPAL_IMPL *"* do not include other source files here!!! interfaces IF_BADI_INTERFACE . interfaces IF_COM_WEC_PSP_INTEGRATION . methods CONSTRUCTOR . protected section. *"* protected components of class ZCL_CRM_PAYPAL_IMPL *"* do not include other source files here!!! private section. *"* private components of class ZCL_CRM_PAYPAL_IMPL *"* do not include other source files here!!! types: begin of LTY_PSP_SHIPPIG_ADDRESS . types TITLE TYPE AD_TITLE. types NAME_FIRST TYPE AD_NAMEFIR. types NAME_LAST TYPE AD_NAMELAS. types NAME2_P TYPE AD_NAME2_P. types NAMEMIDDLE TYPE AD_NAMEMID. types NAME_LAST2 TYPE AD_NAMLAS2. types NICKNAME TYPE AD_NICKNAM. types INITIALS TYPE AD_INITS. types NAME1 TYPE AD_NAME1. types NAME2 TYPE AD_NAME2. types NAME3 TYPE AD_NAME3. types NAME4 TYPE AD_NAME4. types CITY1 TYPE AD_CITY1. types CITY2 TYPE AD_CITY2. types HOME_CITY TYPE AD_CITY3. types POST_CODE1 TYPE AD_PSTCD1. types POST_CODE2 TYPE AD_PSTCD2. types POST_CODE3 TYPE AD_PSTCD3. types PCODE1_EXT TYPE AD_PST1XT. types PCODE2_EXT TYPE AD_PST2XT. types PCODE3_EXT TYPE AD_PST3XT. types PO_BOX TYPE AD_POBX. types PO_BOX_NUM TYPE AD_POBXNUM. types PO_BOX_LOC TYPE AD_POBXLOC. October 2013 261 Development and Extension Guide – Application-Specific Information types PO_BOX_REG TYPE AD_POBXREG. types PO_BOX_CTY TYPE AD_POBXCTY. types STREET TYPE AD_STREET. types HOUSE_NUM1 TYPE AD_HSNM1. types HOUSE_NUM2 TYPE AD_HSNM2. types HOUSE_NUM3 TYPE AD_HSNM3. types STR_SUPPL1 TYPE AD_STRSPP1. types STR_SUPPL2 TYPE AD_STRSPP2. types STR_SUPPL3 type AD_STRSPP3. types LOCATION type AD_LCTN. types BUILDING type AD_BLDNG. types FLOOR type AD_FLOOR. types ROOMNUMBER type AD_ROOMNUM. types COUNTRY type LAND1. types REGION type REGIO. types TAXJURCODE type AD_TXJCD. types end of LTY_PSP_SHIPPIG_ADDRESS . constants GC_SIGNATURE type STRING value `YourPayPalTestAccountSignature`. "#EC NOTEXT constants GC_LOGICAL_PORT type PRX_LOGICAL_PORT_NAME value SPACE. "#EC NOTEXT constants GC_MESSAGE_ID type SYMSGID value 'CRM_WEC_PAYPAL_IMPL'. "#EC NOTEXT constants GC_PAYPAL_CHECKOUT_URL type STRING value `https://www.sandbox.paypal.com/webscr&cmd=_express-checkout&token=`. "#EC NOTEXT constants GC_PAYPAL_PAYMENT_STATUS_COMP type COM_WEC_PAYPAL_PAYMENT_STATUS value `Completed`. "#EC NOTEXT constants GC_PAYPAL_PAYMENT_STATUS_DENI type COM_WEC_PAYPAL_PAYMENT_STATUS value `Denied`. "#EC NOTEXT constants GC_PAYPAL_PAYMENT_STATUS_NONE type COM_WEC_PAYPAL_PAYMENT_STATUS value `None`. "#EC NOTEXT constants GC_PAYPAL_PAYMENT_STATUS_PEND type COM_WEC_PAYPAL_PAYMENT_STATUS value `Pending`. "#EC NOTEXT constants GC_PAYPAL_PAYMENT_STATUS_REFU type COM_WEC_PAYPAL_PAYMENT_STATUS value `Refunded`. "#EC NOTEXT constants GC_PAYPAL_PAYMENT_STATUS_REVE type COM_WEC_PAYPAL_PAYMENT_STATUS value `Reversed`. "#EC NOTEXT data MV_USERNAME type STRING . data MV_PASSWORD type STRING . data MV_TOKEN type COM_WEC_PAYPAL_TOKEN . type-pools ABAP . methods SEARCH_TRANSACTION_BY_REF_ID importing !IV_REFERENCE_ID type COM_WEC_TRANSACTION_ID exporting !EV_ERROR_OCCURRED type ABAP_BOOL !EV_TRANSACTION_EXISTS type ABAP_BOOL !EV_PAYPAL_TRANSACTION_ID type COM_WEC_PAYPAL_TRANSACTION_ID changing !CT_MESSAGES type COMT_WEC_MESSAGES !CT_SYSLOG_MESSAGES type COMT_WEC_MESSAGES . class-methods ADD_MESSAGE importing !IV_TYPE type BAPI_MTYPE !IV_ID type SYMSGID default GC_MESSAGE_ID 262 October 2013 Development and Extension Guide – Application-Specific Information !IV_NUMBER type SYMSGNO !IV_MESSAGE_V1 type SIMPLE optional !IV_MESSAGE_V2 type SIMPLE optional !IV_MESSAGE_V3 type SIMPLE optional !IV_MESSAGE_V4 type SIMPLE optional changing !CT_MESSAGES type COMT_WEC_MESSAGES . class-methods GET_PAYER_ID importing !IT_PARAMETERS type COMT_WEC_HTTP_PARAMETERS returning value(RV_PAYER_ID) type COM_WEC_PAYPAL_PAYER_ID . class-methods GET_SHIPTO_ADDRESS importing !IS_SHIPPING_ADDRESS type ANY returning value(RS_SHIPTO_ADDRESS) type COMS_WEC_PAYPAL_SHIPTO_ADDRESS . methods IS_TOKEN_VALID importing !IT_PARAMETERS type COMT_WEC_HTTP_PARAMETERS returning value(RV_TOKEN_VALID) type ABAP_BOOL . class-methods IS_TRANSACTION_CONFIRMED importing !IT_PARAMETERS type COMT_WEC_HTTP_PARAMETERS returning value(RV_TRANSACTION_CONFIRMED) type COM_WEC_PAYPAL_PAYER_ID . class-methods ADD_API_MESSAGES importing !IT_API_MESSAGES type BAPIRET2_TAB changing !CT_MESSAGES type COMT_WEC_MESSAGES . class-methods REGION_SAP2PP importing !IV_REGIO type REGIO !IV_COUNTRY type LAND1 returning value(RV_REGIO_PP) type STRING . class-methods COUNTRY_SAP2PP importing !IV_COUNTRY type LAND1 returning value(RV_COUNTRY) type STRING . class-methods GET_PASSWORD returning value(RV_PASSWORD) type STRING . class-methods GET_USERNAME returning value(RV_USERNAME) type STRING . ENDCLASS. October 2013 263 Development and Extension Guide – Application-Specific Information CLASS ZCL_CRM_PAYPAL_IMPL IMPLEMENTATION. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_CRM_PAYPAL_IMPL->ADD_API_MESSAGES * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD add_api_messages. * Add API messages to message table DATA ls_message LIKE LINE OF ct_messages. FIELD-SYMBOLS <ls_api_message> LIKE LINE OF it_api_messages. LOOP AT it_api_messages ASSIGNING <ls_api_message>. CLEAR ls_message. MOVE-CORRESPONDING <ls_api_message> TO ls_message. INSERT ls_message INTO TABLE ct_messages. ENDLOOP. ENDMETHOD. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_CRM_PAYPAL_IMPL->ADD_MESSAGE * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD add_message. * Add a message to table CT_MESSAGES DATA ls_message LIKE LINE OF ct_messages. ls_message-type = iv_type. ls_message-id = iv_id. ls_message-number = iv_number. ls_message-message_v1 = iv_message_v1. ls_message-message_v2 = iv_message_v2. ls_message-message_v3 = iv_message_v3. ls_message-message_v4 = iv_message_v4. MESSAGE ID iv_id TYPE iv_type NUMBER iv_number WITH iv_message_v1 iv_message_v2 iv_message_v3 iv_message_v4 INTO ls_message-message. INSERT ls_message INTO TABLE ct_messages. ENDMETHOD. 264 October 2013 Development and Extension Guide – Application-Specific Information * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_CRM_PAYPAL_IMPL->CONSTRUCTOR * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD constructor. * Import user/password for PayPal API from user parameters. If parameters * are not set, use default user/password. mv_username = get_username( ). mv_password = get_password( ). ENDMETHOD. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_CRM_PAYPAL_IMPL->COUNTRY_SAP2PP * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> method COUNTRY_SAP2PP. DATA lv_country_iso TYPE INTCA. CALL FUNCTION 'COUNTRY_CODE_SAP_TO_ISO' EXPORTING sap_code = iv_country IMPORTING ISO_CODE = lv_country_iso EXCEPTIONS NOT_FOUND = 1 OTHERS = 2 . IF sy-subrc <> 0. rv_country = iv_country. ELSE. rv_country = lv_country_iso. ENDIF. endmethod. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_CRM_PAYPAL_IMPL->GET_PASSWORD * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> method GET_PASSWORD. * implement your own logic to determine the password endmethod. October 2013 265 Development and Extension Guide – Application-Specific Information * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_CRM_PAYPAL_IMPL->GET_PAYER_ID * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> method GET_PAYER_ID. * Get the payer ID of the PayPal customer; this is passed in by PayPal in the * redirect to the Web Channel FIELD-SYMBOLS <ls_parameter> TYPE coms_wec_http_parameter. FIELD-SYMBOLS <lv_payer_id> TYPE string. CLEAR rv_payer_id. * Get the payer ID from the HTTP parameters passed in by PayPal READ TABLE it_parameters ASSIGNING <ls_parameter> WITH TABLE KEY name = `PayerID`. * We expect exactly one value for the payer id IF sy-subrc = 0 AND lines( <ls_parameter>-values ) = 1. READ TABLE <ls_parameter>-values ASSIGNING <lv_payer_id> INDEX 1. IF sy-subrc = 0. rv_payer_id = <lv_payer_id>. ENDIF. ENDIF. endmethod. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_CRM_PAYPAL_IMPL->GET_SHIPTO_ADDRESS * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD get_shipto_address. DATA ls_shipping_address TYPE lty_psp_shippig_address. DATA lv_name_string TYPE string. * Convert the internal shipping address to the PayPal shipto address MOVE-CORRESPONDING is_shipping_address TO ls_shipping_address. IF ls_shipping_address-name1 IS NOT INITIAL. lv_name_string = ls_shipping_address-name1. ENDIF. IF ls_shipping_address-name2 IS NOT INITIAL. lv_name_string = lv_name_string && ' ' && ls_shipping_address-name2. ENDIF. IF ls_shipping_address-name3 IS NOT INITIAL. lv_name_string = lv_name_string && ' ' && ls_shipping_address-name3. ENDIF. IF ls_shipping_address-name4 IS NOT INITIAL. lv_name_string = lv_name_string && ' ' && ls_shipping_address-name4. 266 October 2013 Development and Extension Guide – Application-Specific Information ENDIF. IF lv_name_string IS INITIAL. lv_name_string = ls_shipping_address-name_first. IF ls_shipping_address-namemiddle IS NOT INITIAL. lv_name_string = lv_name_string && ' ' && ls_shipping_address-namemiddle. ENDIF. IF ls_shipping_address-name_last IS NOT INITIAL. lv_name_string = lv_name_string && ' ' && ls_shipping_address-name_last. ENDIF. IF ls_shipping_address-name_last2 IS NOT INITIAL. lv_name_string = lv_name_string && ' ' && ls_shipping_address-name_last2. ENDIF. ENDIF. CLEAR rs_shipto_address. rs_shipto_address-name = lv_name_string. rs_shipto_address-street1 = ls_shipping_address-street. rs_shipto_ADDRESS-STREET2 = ls_shipping_address-str_suppl1. rs_shipto_address-city_name = ls_shipping_address-city1. rs_shipto_address-state_or_province = region_sap2pp( iv_regio = ls_shipping_address-region iv_country = ls_shipping_address-country ). rs_shipto_address-country = country_sap2pp( iv_country = ls_shipping_address-country ). rs_shipto_address-postal_code = ls_shipping_address-post_code1. ENDMETHOD. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_CRM_PAYPAL_IMPL->GET_USERNAME * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> method GET_USERNAME. * implement your own logic to determine the username endmethod. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Public Method ZCL_CRM_PAYPAL_IMPL->IF_COM_WEC_PSP_INTEGRATION~CANCEL_TRANSACTION * +--------------------------------------------------------------------------------------------- ----+ * | [--->] IS_REFERENCE_DOCUMENT TYPE COMS_WEC_BUSINESS_OBJECT * | [--->] IV_REFERENCE_GUID TYPE COM_WEC_TRANSACTION_GUID * | [--->] IV_REFERENCE_ID TYPE COM_WEC_TRANSACTION_ID * | [--->] IV_PSP_TRANSACTION_ID TYPE COM_WEC_PSP_TRANSACTION_ID October 2013 267 Development and Extension Guide – Application-Specific Information * | [<---] ER_ACTION TYPE REF TO CL_COM_WEC_CANCEL_TRANS_PARAM * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD if_com_wec_psp_integration~cancel_transaction. * Refund a PayPal transaction after cancelling the corresponding order DATA lv_error_occurred_in_search TYPE abap_bool. DATA lv_transaction_exists TYPE abap_bool. DATA lv_paypal_transaction_id TYPE com_wec_paypal_transaction_id. DATA lt_api_messages TYPE bapiret2_tab. DATA lv_api_success TYPE abap_bool. DATA lt_messages TYPE comt_wec_messages. DATA lt_syslog_messages TYPE comt_wec_messages. * If the PSP transaction ID is given, we assume it is valid and use it to trigger the refunding IF iv_psp_transaction_id IS NOT INITIAL. lv_paypal_transaction_id = iv_psp_transaction_id. * If the refernce ID is given, use it to check if the transaction exists in the PayPal system ELSEIF iv_reference_id IS NOT INITIAL. search_transaction_by_ref_id( EXPORTING iv_reference_id = iv_reference_id IMPORTING ev_error_occurred = lv_error_occurred_in_search ev_transaction_exists = lv_transaction_exists ev_paypal_transaction_id = lv_paypal_transaction_id CHANGING ct_messages = lt_messages ct_syslog_messages = lt_syslog_messages ). * If search failed, reprocess the order later IF lv_error_occurred_in_search = abap_true. CREATE OBJECT er_action TYPE cl_com_wec_reprocess_cancel EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. RETURN. ENDIF. * If transaction is not known in the PayPal system, cancel the order IF lv_transaction_exists = abap_false. CREATE OBJECT er_action TYPE cl_com_wec_finalize_cancel EXPORTING iv_transaction_status_profile = cl_crm_wec_psp_constants=>gc_transaction_status_profile iv_transaction_status = cl_crm_wec_psp_constants=>gc_transaction_status_rfnd. 268 October 2013 Development and Extension Guide – Application-Specific Information RETURN. ENDIF. * Neither PSP transaction ID or reference ID supplied. Give up because a search by transaction GUID * is not supported by PayPal so there is no other option to find the transaction. ELSE. add_message( EXPORTING iv_type = 'E' iv_number = 007 iv_message_v1 = 'GET_TRANSACTION_DETAILS' CHANGING ct_messages = lt_messages ). add_message( EXPORTING iv_type = 'E' iv_number = 007 iv_message_v1 = 'GET_TRANSACTION_DETAILS' CHANGING ct_messages = lt_syslog_messages ). CREATE OBJECT er_action TYPE cl_com_wec_reprocess_cancel EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. RETURN. ENDIF. * Call the PayPal web service to refund the transaction ZCL_COMMON_PAYPAL_API=>refund_transaction( EXPORTING iv_username = mv_username iv_password = mv_password iv_signature = gc_signature iv_logical_port = gc_logical_port iv_transaction_id = lv_paypal_transaction_id iv_refund_type = ZCL_COMMON_PAYPAL_API=>gc_refund_type_full IMPORTING et_messages = lt_api_messages ev_success = lv_api_success ). * Add API messages to application log add_api_messages( EXPORTING it_api_messages = lt_api_messages CHANGING ct_messages = lt_syslog_messages ). October 2013 269 Development and Extension Guide – Application-Specific Information * If refund successfull, finalize the cancellation IF lv_api_success = abap_true. CREATE OBJECT er_action TYPE cl_com_wec_finalize_cancel EXPORTING iv_transaction_status_profile = cl_crm_wec_psp_constants=>gc_transaction_status_profile iv_transaction_status = cl_crm_wec_psp_constants=>gc_transaction_status_rfnd. * If an error occured, schedule for later reprocessing ELSE. add_message( EXPORTING iv_type = 'E' iv_number = 000 iv_message_v1 = 'RefundTransaction' CHANGING ct_messages = lt_messages ). add_message( EXPORTING iv_type = 'E' iv_number = 000 iv_message_v1 = 'RefundTransaction' CHANGING ct_messages = lt_syslog_messages ). CREATE OBJECT er_action TYPE cl_com_wec_reprocess_cancel EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. ENDIF. ENDMETHOD. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Public Method ZCL_CRM_PAYPAL_IMPL- >IF_COM_WEC_PSP_INTEGRATION~GET_TRANSACTION_DETAILS * +--------------------------------------------------------------------------------------------- ----+ * | [--->] IS_REFERENCE_DOCUMENT TYPE COMS_WEC_BUSINESS_OBJECT * | [--->] IV_REFERENCE_GUID TYPE COM_WEC_TRANSACTION_GUID * | [--->] IV_REFERENCE_ID TYPE COM_WEC_TRANSACTION_ID * | [--->] IV_PSP_TRANSACTION_ID TYPE COM_WEC_PSP_TRANSACTION_ID * | [<---] ER_ACTION TYPE REF TO CL_COM_WEC_UPDATE_TRANS_PARAM * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD if_com_wec_psp_integration~get_transaction_details. * Get PayPal transaction details for an order DATA lv_error_occurred_in_search TYPE abap_bool. DATA lv_transaction_exists TYPE abap_bool. DATA lv_paypal_transaction_id TYPE com_wec_paypal_transaction_id. DATA lv_psp_transaction_id TYPE com_wec_psp_transaction_id. 270 October 2013 Development and Extension Guide – Application-Specific Information DATA lv_transaction_amount TYPE com_wec_transaction_amount. DATA lv_transaction_currency TYPE com_wec_transaction_currency. DATA lv_paypal_payment_status TYPE com_wec_paypal_payment_status. DATA lt_api_messages TYPE bapiret2_tab. DATA lv_api_success TYPE abap_bool. DATA lt_messages TYPE comt_wec_messages. DATA lt_syslog_messages TYPE comt_wec_messages. * If the PSP transaction ID is given, we assume it is valid and use it to get the transaction details IF iv_psp_transaction_id IS NOT INITIAL. lv_paypal_transaction_id = iv_psp_transaction_id. * If the refernce ID is given, use it to check if the transaction exists in the PayPal system ELSEIF iv_reference_id IS NOT INITIAL. search_transaction_by_ref_id( EXPORTING iv_reference_id = iv_reference_id IMPORTING ev_error_occurred = lv_error_occurred_in_search ev_transaction_exists = lv_transaction_exists ev_paypal_transaction_id = lv_paypal_transaction_id CHANGING ct_messages = lt_messages ct_syslog_messages = lt_syslog_messages ). * If search failed, reprocess the order later IF lv_error_occurred_in_search = abap_true. CREATE OBJECT er_action TYPE cl_com_wec_reprocess_update EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. RETURN. ENDIF. * If transaction is not known in the PayPal system, cancel the order IF lv_transaction_exists = abap_false. CREATE OBJECT er_action TYPE cl_com_wec_invalidate_trans EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. RETURN. ENDIF. October 2013 271 Development and Extension Guide – Application-Specific Information * Neither PSP transaction ID or reference ID supplied. Give up because a search by transaction GUID * is not supported by PayPal so there is no other option to find the transaction. ELSE. add_message( EXPORTING iv_type = 'E' iv_number = 007 iv_message_v1 = 'GET_TRANSACTION_DETAILS' CHANGING ct_messages = lt_messages ). add_message( EXPORTING iv_type = 'E' iv_number = 007 iv_message_v1 = 'GET_TRANSACTION_DETAILS' CHANGING ct_messages = lt_syslog_messages ). CREATE OBJECT er_action TYPE cl_com_wec_reprocess_update EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. RETURN. ENDIF. * Get transaction details from PayPal ZCL_COMMON_PAYPAL_API=>get_transaction_details( EXPORTING iv_username = mv_username iv_password = mv_password iv_signature = gc_signature iv_logical_port = gc_logical_port iv_transaction_id = lv_paypal_transaction_id IMPORTING ev_payment_status = lv_paypal_payment_status ev_transaction_amount = lv_transaction_amount ev_transaction_currency = lv_transaction_currency et_messages = lt_api_messages ev_success = lv_api_success ). * Put API messages in the application log add_api_messages( EXPORTING it_api_messages = lt_api_messages CHANGING ct_messages = lt_syslog_messages ). * PayPal API call successful -> process PayPal payment status IF lv_api_success = abap_true. 272 October 2013 Development and Extension Guide – Application-Specific Information lv_psp_transaction_id = lv_paypal_transaction_id. CASE lv_paypal_payment_status. * PayPal has no payment status -> cancel corresponding order WHEN gc_paypal_payment_status_none. CREATE OBJECT er_action TYPE cl_com_wec_invalidate_trans EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. * PayPal transaction has status completed -> set PSP status accordingly WHEN gc_paypal_payment_status_comp. CREATE OBJECT er_action TYPE cl_com_wec_update_transaction EXPORTING iv_transaction_status_profile = cl_crm_wec_psp_constants=>gc_transaction_status_profile iv_transaction_status = cl_crm_wec_psp_constants=>gc_transaction_status_comp iv_psp_transaction_id = lv_psp_transaction_id iv_transaction_amount = lv_transaction_amount iv_transaction_currency = lv_transaction_currency it_messages = lt_messages it_syslog_messages = lt_syslog_messages. * PayPal transaction has status pending -> set PSP status accordingly WHEN gc_paypal_payment_status_pend. CREATE OBJECT er_action TYPE cl_com_wec_update_transaction EXPORTING iv_transaction_status_profile = cl_crm_wec_psp_constants=>gc_transaction_status_profile iv_transaction_status = cl_crm_wec_psp_constants=>gc_transaction_status_pend iv_psp_transaction_id = lv_psp_transaction_id iv_transaction_amount = lv_transaction_amount iv_transaction_currency = lv_transaction_currency it_messages = lt_messages it_syslog_messages = lt_syslog_messages. * PayPal transaction has status refunded -> set PSP status accordingly WHEN gc_paypal_payment_status_refu. CREATE OBJECT er_action TYPE cl_com_wec_update_transaction EXPORTING iv_transaction_status_profile = cl_crm_wec_psp_constants=>gc_transaction_status_profile iv_transaction_status = cl_crm_wec_psp_constants=>gc_transaction_status_rfnd iv_psp_transaction_id = lv_psp_transaction_id iv_transaction_amount = lv_transaction_amount iv_transaction_currency = lv_transaction_currency it_messages = lt_messages it_syslog_messages = lt_syslog_messages. * PayPal transaction has status denied -> set PSP status to rejected WHEN gc_paypal_payment_status_deni OR gc_paypal_payment_status_reve. October 2013 273 Development and Extension Guide – Application-Specific Information CREATE OBJECT er_action TYPE cl_com_wec_update_transaction EXPORTING iv_transaction_status_profile = cl_crm_wec_psp_constants=>gc_transaction_status_profile iv_transaction_status = cl_crm_wec_psp_constants=>gc_transaction_status_reje iv_psp_transaction_id = lv_psp_transaction_id iv_transaction_amount = lv_transaction_amount iv_transaction_currency = lv_transaction_currency it_messages = lt_messages it_syslog_messages = lt_syslog_messages. * PayPal returned an unexpected status -> raise an error and reprocess later WHEN OTHERS. add_message( EXPORTING iv_type = 'E' iv_number = 004 iv_message_v1 = 'GetTransactionDetails' iv_message_v2 = lv_paypal_payment_status CHANGING ct_messages = lt_messages ). add_message( EXPORTING iv_type = 'E' iv_number = 004 iv_message_v1 = 'GetTransactionDetails' iv_message_v2 = lv_paypal_payment_status CHANGING ct_messages = lt_syslog_messages ). CREATE OBJECT er_action TYPE cl_com_wec_reprocess_update EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. ENDCASE. * PayPal API returned an error -> reprocess order later ELSE. add_message( EXPORTING iv_type = 'E' iv_number = 000 iv_message_v1 = 'GetTransactionDetails' CHANGING ct_messages = lt_messages ). add_message( EXPORTING iv_type = 'E' iv_number = 000 iv_message_v1 = 'GetTransactionDetails' CHANGING 274 October 2013 Development and Extension Guide – Application-Specific Information ct_messages = lt_syslog_messages ). CREATE OBJECT er_action TYPE cl_com_wec_reprocess_update EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. ENDIF. ENDMETHOD. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Public Method ZCL_CRM_PAYPAL_IMPL->IF_COM_WEC_PSP_INTEGRATION~INITIATE_TRANSACTION * +--------------------------------------------------------------------------------------------- ----+ * | [--->] IS_REFERENCE_DOCUMENT TYPE COMS_WEC_BUSINESS_OBJECT * | [--->] IV_TRANSACTION_AMOUNT TYPE COM_WEC_TRANSACTION_AMOUNT * | [--->] IV_TRANSACTION_CURRENCY TYPE COM_WEC_TRANSACTION_CURRENCY * | [--->] IS_SHIPPING_ADDRESS TYPE COMS_WEC_PAYMENT_ADDR * | [--->] IV_REFERENCE_GUID TYPE COM_WEC_TRANSACTION_GUID * | [--->] IV_REFERENCE_ID TYPE COM_WEC_TRANSACTION_ID * | [--->] IV_WEC_SOURCE_URL TYPE STRING * | [--->] IT_NAME_VALUE TYPE COMT_WEC_PSP_NAME_VALUE_PAIR * | [<---] ER_ACTION TYPE REF TO CL_COM_WEC_CREATE_TRANS_PARAM * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD if_com_wec_psp_integration~initiate_transaction. * Initiate a PayPal transaction (call the PayPal web service SetExpressCheckoutPayment * and redirect the user to the PayPal web site) DATA lv_return_url TYPE string. DATA lv_cancel_url TYPE string. DATA lv_invoice_id TYPE com_wec_paypal_invoice_id. DATA lv_custom TYPE com_wec_paypal_custom. DATA lv_target_url TYPE string. DATA lv_api_success TYPE abap_bool. DATA lt_api_messages TYPE bapiret2_tab. DATA lt_messages TYPE comt_wec_messages. DATA lt_syslog_messages TYPE comt_wec_messages. * Build the return and cancel URLs lv_return_url = iv_wec_source_url && `sap-wec-pp-status=confirmed`. lv_cancel_url = iv_wec_source_url && `sap-wec-pp-status=cancelled`. * Fill invoice ID (order number) and custom field (transaction GUID) lv_invoice_id = iv_reference_id. lv_custom = iv_reference_guid. * Call the PayPal API for starting the checkout ZCL_COMMON_PAYPAL_API=>set_express_checkout( EXPORTING iv_username = mv_username iv_password = mv_password October 2013 275 Development and Extension Guide – Application-Specific Information iv_signature = gc_signature iv_logical_port = gc_logical_port iv_amount = iv_transaction_amount iv_currency = iv_transaction_currency iv_return_url = lv_return_url iv_cancel_url = lv_cancel_url iv_invoice_id = lv_invoice_id iv_custom = lv_custom IMPORTING ev_token = mv_token et_messages = lt_api_messages ev_success = lv_api_success ). * Add API messages to application log add_api_messages( EXPORTING it_api_messages = lt_api_messages CHANGING ct_messages = lt_syslog_messages ). * If an error occured in the API call, output messages and return to checkout page IF lv_api_success = abap_false. add_message( EXPORTING iv_type = 'E' iv_number = 000 iv_message_v1 = 'SetExpressCheckout' CHANGING ct_messages = lt_messages ). add_message( EXPORTING iv_type = 'E' iv_number = 000 iv_message_v1 = 'SetExpressCheckout' CHANGING ct_messages = lt_syslog_messages ). CREATE OBJECT er_action TYPE cl_com_wec_initiate_trans EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. RETURN. ENDIF. * If the token is initial, ouptut messages and return to checkout page IF mv_token IS INITIAL. add_message( EXPORTING iv_type = 'E' iv_number = 001 iv_message_v1 = 'SetExpressCheckout' CHANGING ct_messages = lt_messages ). add_message( 276 October 2013 Development and Extension Guide – Application-Specific Information EXPORTING iv_type = 'E' iv_number = 001 iv_message_v1 = 'SetExpressCheckout' CHANGING ct_messages = lt_syslog_messages ). CREATE OBJECT er_action TYPE cl_com_wec_initiate_trans EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. RETURN. ENDIF. * If we got here no error occured -> redirect the user to PayPal * Add token returned by DoExpressCheckoutPayment to the PayPal URL lv_target_url = gc_paypal_checkout_url && mv_token. * Trigger the redirect CREATE OBJECT er_action TYPE cl_com_wec_trigger_redirect EXPORTING iv_target_url = lv_target_url it_syslog_messages = lt_syslog_messages. ENDMETHOD. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Public Method ZCL_CRM_PAYPAL_IMPL->IF_COM_WEC_PSP_INTEGRATION~PROCESS_CALLBACK * +--------------------------------------------------------------------------------------------- ----+ * | [--->] IS_REFERENCE_DOCUMENT TYPE COMS_WEC_BUSINESS_OBJECT * | [--->] IV_TRANSACTION_AMOUNT TYPE COM_WEC_TRANSACTION_AMOUNT * | [--->] IV_TRANSACTION_CURRENCY TYPE COM_WEC_TRANSACTION_CURRENCY * | [--->] IS_SHIPPING_ADDRESS TYPE COMS_WEC_PAYMENT_ADDR * | [--->] IV_REFERENCE_GUID TYPE COM_WEC_TRANSACTION_GUID * | [--->] IV_REFERENCE_ID TYPE COM_WEC_TRANSACTION_ID * | [--->] IV_WEC_TARGET_URL TYPE STRING * | [--->] IT_PARAMETERS TYPE COMT_WEC_HTTP_PARAMETERS * | [--->] IT_NAME_VALUE TYPE COMT_WEC_PSP_NAME_VALUE_PAIR * | [<---] ER_ACTION TYPE REF TO CL_COM_WEC_CREATE_TRANS_PARAM * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD if_com_wec_psp_integration~process_callback. * Process the redirection from PayPal back to the Web Channel DATA lv_paypal_transaction_id TYPE com_wec_paypal_transaction_id. DATA lv_paypal_payment_status TYPE com_wec_paypal_payment_status. DATA lv_psp_transaction_id TYPE com_wec_psp_transaction_id. DATA lv_api_success TYPE abap_bool. DATA lt_api_messages TYPE bapiret2_tab. DATA lt_messages TYPE comt_wec_messages. October 2013 277 Development and Extension Guide – Application-Specific Information DATA lt_syslog_messages TYPE comt_wec_messages. DATA lv_payer_id(127) TYPE c. DATA lv_cccategory TYPE cccategory. * If the transaction is not confirmed, redirect the user to the checkout page IF is_transaction_confirmed( it_parameters ) = abap_false. add_message( EXPORTING iv_type = 'I' iv_number = 002 CHANGING ct_messages = lt_messages ). add_message( EXPORTING iv_type = 'I' iv_number = 002 CHANGING ct_messages = lt_syslog_messages ). CREATE OBJECT er_action TYPE cl_com_wec_initiate_trans EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. RETURN. ENDIF. * If the token returned by PayPal is invalid, redirect the user to the checkout page IF is_token_valid( it_parameters ) = abap_false. add_message( EXPORTING iv_type = 'E' iv_number = 003 CHANGING ct_messages = lt_messages ). add_message( EXPORTING iv_type = 'E' iv_number = 003 CHANGING ct_messages = lt_syslog_messages ). CREATE OBJECT er_action TYPE cl_com_wec_initiate_trans EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. RETURN. ENDIF. * Call the PayPal API to complete the checkout process ZCL_COMMON_PAYPAL_API=>do_express_checkout_payment( EXPORTING iv_username = mv_username iv_password = mv_password 278 October 2013 Development and Extension Guide – Application-Specific Information iv_signature = gc_signature iv_logical_port = gc_logical_port iv_amount = iv_transaction_amount iv_currency = iv_transaction_currency iv_token = mv_token iv_payerid = get_payer_id( it_parameters ) is_shipto_address = get_shipto_address( is_shipping_address ) IMPORTING ev_transaction_id = lv_paypal_transaction_id ev_payment_status = lv_paypal_payment_status et_messages = lt_api_messages ev_success = lv_api_success ). * Add API messages to application log add_api_messages( EXPORTING it_api_messages = lt_api_messages CHANGING ct_messages = lt_syslog_messages ). * If an error occured in the API call, return the user to the checkout page IF lv_api_success = abap_false OR lv_paypal_transaction_id IS INITIAL. add_message( EXPORTING iv_type = 'E' iv_number = 000 iv_message_v1 = 'DoExpressCheckoutPayment' CHANGING ct_messages = lt_messages ). add_message( EXPORTING iv_type = 'E' iv_number = 000 iv_message_v1 = 'DoExpressCheckoutPayment' CHANGING ct_messages = lt_syslog_messages ). CREATE OBJECT er_action TYPE cl_com_wec_initiate_trans EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. RETURN. ENDIF. * Convert PayPal transaction ID to SAP internal transaction ID lv_psp_transaction_id = lv_paypal_transaction_id. * Check the payment status and finalize the transaction or start over with the checkout CASE lv_paypal_payment_status. WHEN gc_paypal_payment_status_comp. CREATE OBJECT er_action TYPE cl_com_wec_finalize_trans October 2013 279 Development and Extension Guide – Application-Specific Information EXPORTING iv_transaction_status_profile = cl_crm_wec_psp_constants=>gc_transaction_status_profile iv_transaction_status = cl_crm_wec_psp_constants=>gc_transaction_status_comp iv_psp_transaction_id = lv_psp_transaction_id. WHEN gc_paypal_payment_status_pend. CREATE OBJECT er_action TYPE cl_com_wec_finalize_trans EXPORTING iv_transaction_status_profile = cl_crm_wec_psp_constants=>gc_transaction_status_profile iv_transaction_status = cl_crm_wec_psp_constants=>gc_transaction_status_pend iv_psp_transaction_id = lv_psp_transaction_id. WHEN OTHERS. add_message( EXPORTING iv_type = 'E' iv_number = 000 iv_message_v1 = 'DoExpressCheckoutPayment' iv_message_v2 = lv_paypal_payment_status CHANGING ct_messages = lt_messages ). add_message( EXPORTING iv_type = 'E' iv_number = 000 iv_message_v1 = 'DoExpressCheckoutPayment' iv_message_v2 = lv_paypal_payment_status CHANGING ct_messages = lt_syslog_messages ). CREATE OBJECT er_action TYPE cl_com_wec_initiate_trans EXPORTING it_messages = lt_messages it_syslog_messages = lt_syslog_messages. ENDCASE. ENDMETHOD. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_CRM_PAYPAL_IMPL->IS_TOKEN_VALID * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD is_token_valid. * Check if the token returned by PayPal after the redirect to the Web Channel * is the same as supplied by the web service SetExpressCheckout 280 October 2013 Development and Extension Guide – Application-Specific Information FIELD-SYMBOLS <ls_parameter> TYPE coms_wec_http_parameter. FIELD-SYMBOLS <lv_token> TYPE string. rv_token_valid = abap_false. * Read the URL parameter READ TABLE it_parameters ASSIGNING <ls_parameter> WITH TABLE KEY name = `token`. * We expect exactly one value for the token IF sy-subrc = 0 AND lines( <ls_parameter>-values ) = 1. READ TABLE <ls_parameter>-values ASSIGNING <lv_token> INDEX 1. IF sy-subrc = 0 AND mv_token = <lv_token>. rv_token_valid = abap_true. ENDIF. ENDIF. ENDMETHOD. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_CRM_PAYPAL_IMPL->IS_TRANSACTION_CONFIRMED * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD is_transaction_confirmed. * Check if the payment transaction was confirmed by the payer FIELD-SYMBOLS <ls_parameter> TYPE coms_wec_http_parameter. FIELD-SYMBOLS <lv_status> TYPE string. rv_transaction_confirmed = abap_false. * Get the URL parameter from the HTTP parameters passed in by PayPal READ TABLE it_parameters ASSIGNING <ls_parameter> WITH TABLE KEY name = `sap-wec-pp-status`. * We expect exactly one value for the parameter IF sy-subrc = 0 AND lines( <ls_parameter>-values ) = 1. READ TABLE <ls_parameter>-values ASSIGNING <lv_status> INDEX 1. IF sy-subrc = 0 AND <lv_status> = `confirmed`. rv_transaction_confirmed = abap_true. ENDIF. ENDIF. ENDMETHOD. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_CRM_PAYPAL_IMPL->REGION_SAP2PP * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD region_sap2pp. October 2013 281 Development and Extension Guide – Application-Specific Information * region codes of paypal for canada differ from sap region * codes(table T005S). Map the differing ones. CASE iv_country. WHEN 'CA'. CASE iv_regio. WHEN 'NL'. rv_regio_pp = 'NF'. WHEN 'YT'. rv_regio_pp = 'YK'. WHEN OTHERS. rv_regio_pp = iv_regio. ENDCASE. WHEN OTHERS. rv_regio_pp = iv_regio. ENDCASE. ENDMETHOD. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_CRM_PAYPAL_IMPL->SEARCH_TRANSACTION_BY_REF_ID * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD search_transaction_by_ref_id. * Search for a PayPal transaction by our reference ID (= PayPal invoice ID). Note * that searching by our transaction GUID is currently not supported by PayPal's web * services. * Possible return values * * EV_ERROR_OCCURRED = ABAP_FALSE and EV_TRANSACTION_EXISTS = ABAP_TRUE * -> Transaction does exist in the PayPal system. Transaction ID returned in EV_PAYPAL_TRANSACTION_ID * * EV_ERROR_OCCURRED = ABAP_FALSE and EV_TRANSACTION_EXISTS = ABAP_FALSE * -> Transaction does not exist in the PayPal system. * * EV_ERROR_OCCURRED = ABAP_TRUE * -> An error occured when searching in the PayPal system; cannot tell if transactoin * exists or not. * -> More than one transaction found (should never occur) DATA lv_paypal_invoice_id TYPE com_wec_paypal_invoice_id. DATA lv_start_date TYPE timestamp. DATA lt_paypal_transaction_ids TYPE comt_wec_paypal_transaction_id. DATA lt_api_messages TYPE bapiret2_tab. DATA lv_api_success TYPE abap_bool. ev_error_occurred = abap_true. ev_transaction_exists = abap_false. 282 October 2013 Development and Extension Guide – Application-Specific Information CLEAR ev_paypal_transaction_id. * Convert SAP reference ID to PayPal's invoice ID lv_paypal_invoice_id = iv_reference_id. * Set start date for search CONVERT DATE '20000101' TIME '000000' INTO TIME STAMP lv_start_date TIME ZONE 'UTC '. * Execute the search ZCL_COMMON_PAYPAL_API=>transaction_search( EXPORTING iv_username = mv_username iv_password = mv_password iv_signature = gc_signature iv_logical_port = gc_logical_port iv_invoice_id = lv_paypal_invoice_id iv_start_date = lv_start_date IMPORTING et_transaction_ids = lt_paypal_transaction_ids et_messages = lt_api_messages ev_success = lv_api_success ). * Put API messages in the application log add_api_messages( EXPORTING it_api_messages = lt_api_messages CHANGING ct_messages = ct_syslog_messages ). * API call not successfull -> add error and return IF lv_api_success = abap_false. add_message( EXPORTING iv_type = 'E' iv_number = 005 iv_message_v1 = iv_reference_id CHANGING ct_messages = ct_messages ). add_message( EXPORTING iv_type = 'E' iv_number = 005 iv_message_v1 = iv_reference_id CHANGING ct_messages = ct_syslog_messages ). RETURN. ENDIF. * More than one transaction found for the reference number; this indicates a potential * error in the SAP system -> add error and return IF lines( lt_paypal_transaction_ids ) > 1. add_message( October 2013 283 Development and Extension Guide – Application-Specific Information EXPORTING iv_type = 'E' iv_number = 006 iv_message_v1 = iv_reference_id CHANGING ct_messages = ct_messages ). add_message( EXPORTING iv_type = 'E' iv_number = 006 iv_message_v1 = iv_reference_id CHANGING ct_messages = ct_syslog_messages ). RETURN. ENDIF. * If we got here, the API call was successful and returned no transaction ID * (transaction not known in the PayPal system) or one transaction ID (transaction * known in the PayPal system) ev_error_occurred = abap_false. * Read transaction ID if any READ TABLE lt_paypal_transaction_ids INTO ev_paypal_transaction_id INDEX 1. IF sy-subrc = 0 AND ev_paypal_transaction_id IS NOT INITIAL. ev_transaction_exists = abap_true. ENDIF. ENDMETHOD. ENDCLASS. Sample helper class ZCL_COMMON_PAYPAL_API: class ZCL_COMMON_PAYPAL_API definition public final create public . public section. *"* public components of class ZCL_COMMON_PAYPAL_API *"* do not include other source files here!!! type-pools ABAP . constants GC_PAYPAL_API_VERSION type STRING value '60.0'. "#EC NOTEXT constants GC_PAYMENT_ACTION_NONE type COM_WEC_PAYPAL_PAYMENT_ACTION value 'None'. "#EC NOTEXT constants GC_PAYMENT_ACTION_SALE type COM_WEC_PAYPAL_PAYMENT_ACTION value 'Sale'. "#EC NOTEXT constants GC_PAYMENT_ACTION_AUTH type COM_WEC_PAYPAL_PAYMENT_ACTION value 'Authorization'. "#EC NOTEXT constants GC_PAYMENT_ACTION_ORDER type COM_WEC_PAYPAL_PAYMENT_ACTION value 'Order'. "#EC NOTEXT constants GC_REFUND_TYPE_OTHER type COM_WEC_PAYPAL_REFUND_TYPE value 'Other'. "#EC NOTEXT constants GC_REFUND_TYPE_FULL type COM_WEC_PAYPAL_REFUND_TYPE value 'Full'. "#EC NOTEXT constants GC_REFUND_TYPE_PARTIAL type COM_WEC_PAYPAL_REFUND_TYPE value 'Partial'. "#EC NOTEXT constants GC_ACK_SUCCESS type COM_WEC_PAYPAL_ACKNOWLEDGEMENT value 'Success'. "#EC NOTEXT constants GC_ACK_FAILURE type COM_WEC_PAYPAL_ACKNOWLEDGEMENT value 'Failure'. "#EC NOTEXT 284 October 2013 Development and Extension Guide – Application-Specific Information constants GC_ACK_WARNING type COM_WEC_PAYPAL_ACKNOWLEDGEMENT value 'Warning'. "#EC NOTEXT constants GC_ACK_SUCCESSWITHWARNING type COM_WEC_PAYPAL_ACKNOWLEDGEMENT value 'SuccessWithWarning'. "#EC NOTEXT constants GC_ACK_FAILUREWITHWARNING type COM_WEC_PAYPAL_ACKNOWLEDGEMENT value 'FailureWithWarning'. "#EC NOTEXT constants GC_ACK_CUSTOMCODE type COM_WEC_PAYPAL_ACKNOWLEDGEMENT value 'CustomCode'. "#EC NOTEXT constants GC_SEVERITY_CODE_WARNING type COM_WEC_PAYPAL_SEVERITY_CODE value 'Warning'. "#EC NOTEXT constants GC_SEVERITY_CODE_ERROR type COM_WEC_PAYPAL_SEVERITY_CODE value 'Error'. "#EC NOTEXT constants GC_SEVERITY_CODE_CUSTOM type COM_WEC_PAYPAL_SEVERITY_CODE value 'CustomCode'. "#EC NOTEXT class-methods SET_EXPRESS_CHECKOUT importing !IV_USERNAME type STRING !IV_PASSWORD type STRING !IV_SIGNATURE type STRING optional !IV_LOGICAL_PORT type PRX_LOGICAL_PORT_NAME optional !IV_AMOUNT type COM_WEC_TRANSACTION_AMOUNT !IV_CURRENCY type COM_WEC_TRANSACTION_CURRENCY !IV_RETURN_URL type STRING !IV_CANCEL_URL type STRING !IV_INVOICE_ID type COM_WEC_PAYPAL_INVOICE_ID optional !IV_CUSTOM type COM_WEC_PAYPAL_CUSTOM optional exporting !EV_TOKEN type COM_WEC_PAYPAL_TOKEN !ET_MESSAGES type BAPIRET2_TAB !EV_SUCCESS type ABAP_BOOL . class-methods DO_EXPRESS_CHECKOUT_PAYMENT importing !IV_USERNAME type STRING !IV_PASSWORD type STRING !IV_SIGNATURE type STRING optional !IV_LOGICAL_PORT type PRX_LOGICAL_PORT_NAME optional !IV_AMOUNT type COM_WEC_TRANSACTION_AMOUNT !IV_CURRENCY type COM_WEC_TRANSACTION_CURRENCY !IV_TOKEN type COM_WEC_PAYPAL_TOKEN !IV_PAYERID type COM_WEC_PAYPAL_PAYER_ID !IS_SHIPTO_ADDRESS type COMS_WEC_PAYPAL_SHIPTO_ADDRESS exporting !EV_TRANSACTION_ID type COM_WEC_PAYPAL_TRANSACTION_ID !EV_PAYMENT_STATUS type COM_WEC_PAYPAL_PAYMENT_STATUS !EV_PENDING_REASON type COM_WEC_PAYPAL_PENDING_REASON !ET_MESSAGES type BAPIRET2_TAB !EV_SUCCESS type ABAP_BOOL . class-methods GET_EXPRESS_CHECKOUT_DETAILS importing !IV_USERNAME type STRING !IV_PASSWORD type STRING !IV_SIGNATURE type STRING optional !IV_LOGICAL_PORT type PRX_LOGICAL_PORT_NAME optional !IV_TOKEN type COM_WEC_PAYPAL_TOKEN exporting October 2013 285 Development and Extension Guide – Application-Specific Information !EV_PAYER_ID type COM_WEC_PAYPAL_PAYER_ID !EV_INVOICE_ID type COM_WEC_PAYPAL_INVOICE_ID !EV_CUSTOM type COM_WEC_PAYPAL_CUSTOM !ET_MESSAGES type BAPIRET2_TAB !EV_SUCCESS type ABAP_BOOL . class-methods GET_TRANSACTION_DETAILS importing !IV_USERNAME type STRING !IV_PASSWORD type STRING !IV_SIGNATURE type STRING optional !IV_LOGICAL_PORT type PRX_LOGICAL_PORT_NAME optional !IV_TRANSACTION_ID type COM_WEC_PAYPAL_TRANSACTION_ID exporting !EV_PAYMENT_STATUS type COM_WEC_PAYPAL_PAYMENT_STATUS !EV_PENDING_REASON type COM_WEC_PAYPAL_PENDING_REASON !EV_PAYER_ID type COM_WEC_PAYPAL_PAYER_ID !EV_INVOICE_ID type COM_WEC_PAYPAL_INVOICE_ID !EV_CUSTOM type COM_WEC_PAYPAL_CUSTOM !EV_TRANSACTION_AMOUNT type COM_WEC_TRANSACTION_AMOUNT !EV_TRANSACTION_CURRENCY type COM_WEC_TRANSACTION_CURRENCY !ET_MESSAGES type BAPIRET2_TAB !EV_SUCCESS type ABAP_BOOL . class-methods TRANSACTION_SEARCH importing !IV_USERNAME type STRING !IV_PASSWORD type STRING !IV_SIGNATURE type STRING !IV_LOGICAL_PORT type PRX_LOGICAL_PORT_NAME !IV_TRANSACTION_ID type COM_WEC_PAYPAL_TRANSACTION_ID optional !IV_INVOICE_ID type COM_WEC_PAYPAL_INVOICE_ID optional !IV_AMOUNT type COM_WEC_TRANSACTION_AMOUNT optional !IV_CURRENCY type COM_WEC_TRANSACTION_CURRENCY optional !IV_START_DATE type TIMESTAMP !IV_END_DATE type TIMESTAMP optional exporting !ET_TRANSACTION_IDS type COMT_WEC_PAYPAL_TRANSACTION_ID !ET_MESSAGES type BAPIRET2_TAB !EV_SUCCESS type ABAP_BOOL . class-methods REFUND_TRANSACTION importing !IV_USERNAME type STRING !IV_PASSWORD type STRING !IV_SIGNATURE type STRING optional !IV_LOGICAL_PORT type PRX_LOGICAL_PORT_NAME optional !IV_AMOUNT type COM_WEC_TRANSACTION_AMOUNT optional !IV_CURRENCY type COM_WEC_TRANSACTION_CURRENCY optional !IV_TRANSACTION_ID type COM_WEC_PAYPAL_TRANSACTION_ID !IV_REFUND_TYPE type COM_WEC_PAYPAL_REFUND_TYPE !IV_MEMO type COM_WEC_PAYPAL_MEMO optional exporting !EV_REFUND_TRANS_ID type COM_WEC_PAYPAL_REFUND_TRANS_ID !ET_MESSAGES type BAPIRET2_TAB !EV_SUCCESS type ABAP_BOOL . 286 October 2013 Development and Extension Guide – Application-Specific Information protected section. *"* protected components of class ZCL_COMMON_PAYPAL_API *"* do not include other source files here!!! private section. *"* private components of class ZCL_COMMON_PAYPAL_API *"* do not include other source files here!!! constants GC_PAYPAL_PAYMENT_STATUS_NONE type COM_WEC_PAYPAL_PAYMENT_STATUS value 'None'. "#EC NOTEXT class-methods GET_SOAP_HEADER_AUTH importing !IV_USERNAME type STRING !IV_PASSWORD type STRING !IV_SIGNATURE type STRING optional exporting !ER_XML_DOCUMENT type ref to IF_IXML_DOCUMENT . class-methods ADD_TO_SOAP_HEADER importing !IR_XML_DOCUMENT type ref to IF_IXML_DOCUMENT !IR_PROTOCOL type ref to IF_WSPROTOCOL_WS_HEADER . class-methods GET_WS_INTERFACE importing !IV_USERNAME type STRING !IV_PASSWORD type STRING !IV_SIGNATURE type STRING optional !IV_LOGICAL_PORT type PRX_LOGICAL_PORT_NAME optional exporting !ER_INTERFACE type ref to CO_PAY_PAL_APIAAINTERFACE . class-methods GET_WS_INTERFACE_FOR_TRANS importing !IV_USERNAME type STRING !IV_PASSWORD type STRING !IV_SIGNATURE type STRING optional !IV_LOGICAL_PORT type PRX_LOGICAL_PORT_NAME optional exporting !ER_INTERFACE type ref to CO_PAY_PAL_APIINTERFACE . class-methods GET_ERRORS_FROM_PAYPAL importing !IS_ABSTRACT_RESPONSE_TYPE type ABSTRACT_RESPONSE_TYPE !IV_RETURNED_VALUE type ANY exporting !ET_MESSAGES type BAPIRET2_TAB !EV_SUCCESS type ABAP_BOOL . ENDCLASS. CLASS ZCL_COMMON_PAYPAL_API IMPLEMENTATION. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ October 2013 287 Development and Extension Guide – Application-Specific Information * | Instance Private Method ZCL_COMMON_PAYPAL_API->ADD_TO_SOAP_HEADER * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> method ADD_TO_SOAP_HEADER. DATA: l_root TYPE REF TO if_ixml_element, l_element TYPE REF TO if_ixml_element, lv_element_name TYPE string, lv_namespace TYPE string. * Get root element l_root = ir_xml_document->get_root_element( ). * Get first child element l_element ?= l_root->get_first_child( ). * Loop over all child elements WHILE NOT l_element IS INITIAL. * Get element name and namespace lv_element_name = l_element->get_name( ). lv_namespace = l_element->get_namespace_uri( ). * Add header element to SOAP header ir_protocol->set_request_header( name = lv_element_name namespace = lv_namespace dom = l_element ). * Get next element l_element ?= l_element->get_next( ). ENDWHILE. endmethod. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_COMMON_PAYPAL_API->DO_EXPRESS_CHECKOUT_PAYMENT * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> method DO_EXPRESS_CHECKOUT_PAYMENT. DATA: lv_iso_langu TYPE laiso, lv_iso_currency TYPE tcurc-isocd, ls_request TYPE doexpress_checkout_payment_r7, ls_response TYPE doexpress_checkout_payment_r6, ls_payment_info TYPE payment_info_type, ls_abstract_request_type TYPE abstract_request_type, ls_set_express_checkout_req TYPE doexpress_checkout_payment_r5, ls_payment_details TYPE payment_details_type, 288 October 2013 Development and Extension Guide – Application-Specific Information lr_ws_proxy TYPE REF TO co_pay_pal_apiaainterface, le_root TYPE REF TO cx_root, ls_message TYPE bapiret2. TRY. * Convert language key to ISO language code CALL METHOD cl_gdt_conversion=>language_code_outbound EXPORTING im_value = sy-langu IMPORTING ex_value = lv_iso_langu. * Convert currency key to ISO currency code CALL METHOD cl_gdt_conversion=>currency_code_outbound EXPORTING im_value = iv_currency IMPORTING ex_value = lv_iso_currency. * fill request data ls_abstract_request_type-error_language = lv_iso_langu. ls_abstract_request_type-version = gc_paypal_api_version. ls_payment_details-order_total-currency_id = lv_iso_currency. ls_payment_details-order_total-content = iv_amount. MOVE-CORRESPONDING is_shipto_address TO ls_payment_details-ship_to_address. * At the moment only advance payment is supported ls_set_express_checkout_req-payment_action = ZCL_COMMON_PAYPAL_API=>gc_payment_action_sale. ls_set_express_checkout_req-token = iv_token. ls_set_express_checkout_req-payer_id = iv_payerid. ls_set_express_checkout_req-payment_details = ls_payment_details. ls_request-do_express_checkout_payment_re-base = ls_abstract_request_type. ls_request-do_express_checkout_payment_re-do_express_checkout_payment_re = ls_set_express_checkout_req. * Get webservice proxy CALL METHOD get_ws_interface EXPORTING iv_username = iv_username iv_password = iv_password iv_signature = iv_signature iv_logical_port = iv_logical_port IMPORTING er_interface = lr_ws_proxy. * Call webservice proxy CALL METHOD lr_ws_proxy->do_express_checkout_payment EXPORTING input = ls_request IMPORTING October 2013 289 Development and Extension Guide – Application-Specific Information output = ls_response. * Error handling CATCH cx_gdt_conversion cx_ai_system_fault cx_ai_application_fault INTO le_root. ls_message-type = 'E'. ls_message-message = le_root->if_message~get_text( ). CALL FUNCTION 'OWN_LOGICAL_SYSTEM_GET' IMPORTING own_logical_system = ls_message-system. APPEND ls_message TO et_messages. CLEAR ls_message. ev_success = abap_false. RETURN. ENDTRY. * Return transaction ID and payment status ls_payment_info = ls_response-do_express_checkout_payment_re-do_express_checkout_payment_re- payment_info. ev_transaction_id = ls_payment_info-transaction_id. ev_payment_status = ls_payment_info-payment_status. ev_pending_reason = ls_payment_info-pending_reason. * Handling of errors returned by PayPal CALL METHOD get_errors_from_paypal EXPORTING is_abstract_response_type = ls_response-do_express_checkout_payment_re-base iv_returned_value = ev_transaction_id IMPORTING et_messages = et_messages ev_success = ev_success. endmethod. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_COMMON_PAYPAL_API->GET_ERRORS_FROM_PAYPAL * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> method GET_ERRORS_FROM_PAYPAL. DATA: ls_message TYPE bapiret2. FIELD-SYMBOLS: <ls_paypal_error> TYPE error_type3. * Error detection CASE is_abstract_response_type-ack. WHEN gc_ack_success. ev_success = abap_true. 290 October 2013 Development and Extension Guide – Application-Specific Information WHEN gc_ack_successwithwarning. ev_success = abap_true. WHEN gc_ack_failure. ev_success = abap_false. WHEN gc_ack_failurewithwarning. ev_success = abap_false. * For the values below we cannot be really sure whether the operation was successful. * Therefore, the parameter returned by PayPal is checked. If it is provided, the * operation was successful - otherwise it failed. For example, if the method * set_express_checkout returns with a warning but the token is returned from * PayPal, the operation was a success. WHEN gc_ack_warning. IF iv_returned_value IS INITIAL. ev_success = abap_false. ELSE. ev_success = abap_true. ENDIF. WHEN gc_ack_customcode. "Reserved by PayPal for internal or future use IF iv_returned_value IS INITIAL. ev_success = abap_false. ELSE. ev_success = abap_true. ENDIF. WHEN OTHERS. IF iv_returned_value IS INITIAL. ev_success = abap_false. ELSE. ev_success = abap_true. ENDIF. ENDCASE. * Loop over all messages returned from PayPal LOOP AT is_abstract_response_type-errors ASSIGNING <ls_paypal_error>. CASE <ls_paypal_error>-severity_code. WHEN gc_severity_code_warning. ls_message-type = 'W'. WHEN gc_severity_code_error. ls_message-type = 'E'. WHEN gc_severity_code_custom. "Reserved by PayPal for internal or future use ls_message-type = 'I'. ENDCASE. ls_message-message = <ls_paypal_error>-short_message. APPEND ls_message TO et_messages. CLEAR ls_message. ENDLOOP. endmethod. October 2013 291 Development and Extension Guide – Application-Specific Information * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_COMMON_PAYPAL_API->GET_EXPRESS_CHECKOUT_DETAILS * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD get_express_checkout_details. DATA: lv_iso_langu TYPE laiso, ls_request TYPE get_express_checkout_details_5, ls_response TYPE get_express_checkout_details_4, ls_checkout_details TYPE get_express_checkout_details_3, ls_abstract_request_type TYPE abstract_request_type, lr_ws_proxy TYPE REF TO co_pay_pal_apiaainterface, le_root TYPE REF TO cx_root, ls_message TYPE bapiret2. TRY. * Convert language key to ISO language code CALL METHOD cl_gdt_conversion=>language_code_outbound EXPORTING im_value = sy-langu IMPORTING ex_value = lv_iso_langu. * fill request data ls_abstract_request_type-error_language = lv_iso_langu. ls_abstract_request_type-version = gc_paypal_api_version. ls_request-get_express_checkout_details_r-base = ls_abstract_request_type. ls_request-get_express_checkout_details_r-token = iv_token. * Get webservice proxy CALL METHOD get_ws_interface EXPORTING iv_username = iv_username iv_password = iv_password iv_signature = iv_signature iv_logical_port = iv_logical_port IMPORTING er_interface = lr_ws_proxy. * Call proxy CALL METHOD lr_ws_proxy->get_express_checkout_details EXPORTING input = ls_request IMPORTING output = ls_response. * Error handling CATCH cx_gdt_conversion cx_ai_system_fault cx_ai_application_fault INTO le_root. 292 October 2013 Development and Extension Guide – Application-Specific Information ls_message-type = 'E'. ls_message-message = le_root->if_message~get_text( ). CALL FUNCTION 'OWN_LOGICAL_SYSTEM_GET' IMPORTING own_logical_system = ls_message-system. APPEND ls_message TO et_messages. CLEAR ls_message. ev_success = abap_false. RETURN. ENDTRY. * Return Payer ID, Invoice ID, and Custom field ls_checkout_details = ls_response-get_express_checkout_details_r- get_express_checkout_details_r. ev_payer_id = ls_checkout_details-payer_info-payer_id. ev_invoice_id = ls_checkout_details-invoice_id. ev_custom = ls_checkout_details-custom. * Handling of errors returned by PayPal CALL METHOD get_errors_from_paypal EXPORTING is_abstract_response_type = ls_response-get_express_checkout_details_r-base iv_returned_value = ev_payer_id IMPORTING et_messages = et_messages ev_success = ev_success. ENDMETHOD. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_COMMON_PAYPAL_API->GET_SOAP_HEADER_AUTH * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD get_soap_header_auth. CONSTANTS: co_tag_header TYPE string VALUE 'Header', "#EC NOTEXT co_tag_req_cred TYPE string VALUE 'RequesterCredentials', "#EC NOTEXT co_tag_credentials TYPE string VALUE 'Credentials', "#EC NOTEXT co_tag_username TYPE string VALUE 'Username', "#EC NOTEXT co_tag_password TYPE string VALUE 'Password', "#EC NOTEXT co_tag_signature TYPE string VALUE 'Signature', "#EC NOTEXT co_attr_xmlns TYPE string VALUE 'xmlns', "#EC NOTEXT co_attr_type TYPE string VALUE 'type', "#EC NOTEXT co_namesp_soap TYPE string VALUE 'SOAP-ENV', "#EC NOTEXT co_namesp_xsi TYPE string VALUE 'xsi', "#EC NOTEXT co_ns_paypalapi TYPE string VALUE 'urn:ebay:api:PayPalAPI', "#EC NOTEXT co_ns_eblbase TYPE string VALUE 'urn:ebay:apis:eBLBaseComponents', "#EC NOTEXT October 2013 293 Development and Extension Guide – Application-Specific Information co_ns_xsi TYPE string VALUE 'http://www.w3.org/2001/XMLSchema-instance', "#EC NOTEXT co_ns_enc TYPE string VALUE 'http://schemas.xmlsoap.org/soap/encoding/', "#EC NOTEXT co_ns_env TYPE string VALUE 'http://schemas.xmlsoap.org/soap/envelope/', "#EC NOTEXT co_ns_xsd TYPE string VALUE 'http://www.w3.org/2001/XMLSchema', "#EC NOTEXT co_ns_encoding TYPE string VALUE 'http://schemas.xmlsoap.org/soap/encoding/', "#EC NOTEXT co_ns_security_h TYPE string VALUE 'ebl:CustomSecurityHeaderType', "#EC NOTEXT co_ns_base_comp TYPE string VALUE 'urn:ebay:apis:eBLBaseComponents', "#EC NOTEXT co_ns_user_pwd TYPE string VALUE 'ebl:UserIdPasswordType'. "#EC NOTEXT DATA: l_ixml TYPE REF TO if_ixml, l_document TYPE REF TO if_ixml_document, l_encoding TYPE REF TO if_ixml_encoding, l_root TYPE REF TO if_ixml_element, l_req_cred TYPE REF TO if_ixml_element, l_credentials TYPE REF TO if_ixml_element, l_username TYPE REF TO if_ixml_element, l_password TYPE REF TO if_ixml_element, l_signature TYPE REF TO if_ixml_element, l_rc LIKE sy-subrc. * Initialize the iXML-Toolkit l_ixml = cl_ixml=>create( ). * Create the xml-document l_document = l_ixml->create_document( ). * Set encoding to UTF-8 l_encoding = l_ixml->create_encoding( byte_order = 0 " little endian byte ordering character_set = 'UTF-8' ). CALL METHOD l_document->set_encoding EXPORTING encoding = l_encoding. * Create the root element (SOAP header) l_root = l_document->create_simple_element( name = co_tag_header namespace = co_namesp_soap parent = l_document ). * Create the element RequesterCredentials l_req_cred = l_document->create_simple_element( name = co_tag_req_cred parent = l_root ). * Create the element Credentials l_credentials = l_document->create_simple_element( name = co_tag_credentials parent = l_req_cred ). 294 October 2013 Development and Extension Guide – Application-Specific Information * Create the element Username l_username = l_document->create_simple_element( name = co_tag_username value = iv_username parent = l_credentials ). * Create the element Password l_password = l_document->create_simple_element( name = co_tag_password value = iv_password parent = l_credentials ). * Create the element Signature IF iv_signature IS NOT INITIAL. l_signature = l_document->create_simple_element( name = co_tag_signature value = iv_signature parent = l_credentials ). ENDIF. * Add attributes to the elements l_rc = l_req_cred->set_attribute( name = co_attr_xmlns value = co_ns_paypalapi ). l_rc = l_req_cred->set_attribute( name = co_namesp_xsi namespace = co_attr_xmlns value = co_ns_xsi ). l_rc = l_req_cred->set_attribute( name = co_attr_type namespace = co_namesp_xsi value = co_ns_security_h ). l_rc = l_credentials->set_attribute( name = co_attr_xmlns value = co_ns_base_comp ). l_rc = l_credentials->set_attribute( name = co_attr_type namespace = co_namesp_xsi value = co_ns_user_pwd ). er_xml_document = l_document. ENDMETHOD. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_COMMON_PAYPAL_API->GET_TRANSACTION_DETAILS * +--------------------------------------------------------------------------------------------- ----+ October 2013 295 Development and Extension Guide – Application-Specific Information * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD get_transaction_details. DATA: lv_iso_langu TYPE laiso, ls_request TYPE get_transaction_details_reque1, ls_response TYPE get_transaction_details_respo1, ls_transaction_details TYPE payment_transaction_details, ls_abstract_request_type TYPE abstract_request_type, lr_ws_proxy TYPE REF TO co_pay_pal_apiinterface, le_root TYPE REF TO cx_root, ls_message TYPE bapiret2. TRY. * Convert language key to ISO language code CALL METHOD cl_gdt_conversion=>language_code_outbound EXPORTING im_value = sy-langu IMPORTING ex_value = lv_iso_langu. * fill request data ls_abstract_request_type-error_language = lv_iso_langu. ls_abstract_request_type-version = gc_paypal_api_version. ls_request-get_transaction_details_reques-base = ls_abstract_request_type. ls_request-get_transaction_details_reques-transaction_id = iv_transaction_id. * Get webservice proxy CALL METHOD get_ws_interface_for_trans EXPORTING iv_username = iv_username iv_password = iv_password iv_signature = iv_signature iv_logical_port = iv_logical_port IMPORTING er_interface = lr_ws_proxy. * Call webservice proxy CALL METHOD lr_ws_proxy->get_transaction_details EXPORTING input = ls_request IMPORTING output = ls_response. * Error handling CATCH cx_gdt_conversion cx_ai_system_fault cx_ai_application_fault INTO le_root. ls_message-type = 'E'. ls_message-message = le_root->if_message~get_text( ). CALL FUNCTION 'OWN_LOGICAL_SYSTEM_GET' IMPORTING own_logical_system = ls_message-system. 296 October 2013 Development and Extension Guide – Application-Specific Information APPEND ls_message TO et_messages. CLEAR ls_message. ev_success = abap_false. RETURN. ENDTRY. * Return transaction details ls_transaction_details = ls_response-get_transaction_details_respon- payment_transaction_details. ev_payment_status = ls_transaction_details-payment_info-payment_status. ev_pending_reason = ls_transaction_details-payment_info-pending_reason. ev_payer_id = ls_transaction_details-payer_info-payer_id. ev_invoice_id = ls_transaction_details-payment_item_info-invoice_id. ev_custom = ls_transaction_details-payment_item_info-custom. ev_transaction_amount = ls_transaction_details-payment_info-gross_amount-content. ev_transaction_currency = ls_transaction_details-payment_info-gross_amount-currency_id. * Handling of errors returned by PayPal CALL METHOD get_errors_from_paypal EXPORTING is_abstract_response_type = ls_response-get_transaction_details_respon-base iv_returned_value = ls_transaction_details-payment_info-transaction_id IMPORTING et_messages = et_messages ev_success = ev_success. ENDMETHOD. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_COMMON_PAYPAL_API->GET_WS_INTERFACE * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> method GET_WS_INTERFACE. DATA: lr_protocol TYPE REF TO if_wsprotocol_ws_header, lr_xml_document TYPE REF TO if_ixml_document, le_system_fault TYPE REF TO cx_ai_system_fault, lv_text TYPE string. TRY. * Create instance CREATE OBJECT er_interface EXPORTING logical_port_name = iv_logical_port. * Get the web service protocol for access to additional fields of the WS SOAP message header lr_protocol ?= er_interface->get_protocol( if_wsprotocol=>ws_header ). October 2013 297 Development and Extension Guide – Application-Specific Information * Get additional fields for the authentication in the SOAP header CALL METHOD get_soap_header_auth EXPORTING iv_username = iv_username iv_password = iv_password iv_signature = iv_signature IMPORTING er_xml_document = lr_xml_document. * Add additional fields to the SOAP header CALL METHOD add_to_soap_header EXPORTING ir_xml_document = lr_xml_document ir_protocol = lr_protocol. CATCH cx_ai_system_fault INTO le_system_fault. lv_text = le_system_fault->if_message~get_text( ). MESSAGE lv_text TYPE 'X'. ENDTRY. endmethod. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_COMMON_PAYPAL_API->GET_WS_INTERFACE_FOR_TRANS * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> method GET_WS_INTERFACE_FOR_TRANS. DATA: lr_protocol TYPE REF TO if_wsprotocol_ws_header, lr_xml_document TYPE REF TO if_ixml_document, le_system_fault TYPE REF TO cx_ai_system_fault, lv_text TYPE string. TRY. * Create instance CREATE OBJECT er_interface EXPORTING logical_port_name = iv_logical_port. * Get the web service protocol for access to additional fields of the WS SOAP message header lr_protocol ?= er_interface->get_protocol( if_wsprotocol=>ws_header ). * Get additional fields for the authentication in the SOAP header CALL METHOD get_soap_header_auth EXPORTING iv_username = iv_username iv_password = iv_password iv_signature = iv_signature 298 October 2013 Development and Extension Guide – Application-Specific Information IMPORTING er_xml_document = lr_xml_document. * Add additional fields to the SOAP header CALL METHOD add_to_soap_header EXPORTING ir_xml_document = lr_xml_document ir_protocol = lr_protocol. CATCH cx_ai_system_fault INTO le_system_fault. lv_text = le_system_fault->if_message~get_text( ). MESSAGE lv_text TYPE 'X'. ENDTRY. endmethod. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_COMMON_PAYPAL_API->REFUND_TRANSACTION * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> method REFUND_TRANSACTION. DATA: lv_iso_langu TYPE laiso, lv_iso_currency TYPE tcurc-isocd, ls_request TYPE refund_transaction_request, ls_response TYPE refund_transaction_response, ls_abstract_request_type TYPE abstract_request_type, lr_ws_proxy TYPE REF TO co_pay_pal_apiinterface, le_root TYPE REF TO cx_root, ls_message TYPE bapiret2. TRY. * Convert language key to ISO language code CALL METHOD cl_gdt_conversion=>language_code_outbound EXPORTING im_value = sy-langu IMPORTING ex_value = lv_iso_langu. * In case of partial refunding IF iv_refund_type EQ ZCL_COMMON_PAYPAL_API=>gc_refund_type_partial. * If the amount to be refunded is not provided IF iv_currency IS INITIAL OR iv_amount IS INITIAL. * An amount and a currency must be provided for partial refunding MESSAGE e015 INTO ls_message-message. CALL FUNCTION 'BALW_BAPIRETURN_GET2' October 2013 299 Development and Extension Guide – Application-Specific Information EXPORTING type = sy-msgty cl = sy-msgid number = sy-msgno par1 = sy-msgv1 par2 = sy-msgv2 par3 = sy-msgv3 par4 = sy-msgv4 IMPORTING return = ls_message. APPEND ls_message TO et_messages. CLEAR ls_message. ev_success = abap_false. RETURN. ENDIF. "If the amount to be refunded is not provided * Convert currency key to ISO currency code CALL METHOD cl_gdt_conversion=>currency_code_outbound EXPORTING im_value = iv_currency IMPORTING ex_value = lv_iso_currency. ENDIF. "In case of partial refunding * fill request data ls_abstract_request_type-error_language = lv_iso_langu. ls_abstract_request_type-version = gc_paypal_api_version. ls_request-refund_transaction_request-base = ls_abstract_request_type. ls_request-refund_transaction_request-transaction_id = iv_transaction_id. ls_request-refund_transaction_request-refund_type = iv_refund_type. ls_request-refund_transaction_request-memo = iv_memo. * In case of partial refunding IF iv_refund_type EQ ZCL_COMMON_PAYPAL_API=>gc_refund_type_partial. ls_request-refund_transaction_request-amount-currency_id = iv_currency. ls_request-refund_transaction_request-amount-content = iv_amount. ENDIF. * Get webservice proxy CALL METHOD get_ws_interface_for_trans EXPORTING iv_username = iv_username iv_password = iv_password iv_signature = iv_signature iv_logical_port = iv_logical_port IMPORTING er_interface = lr_ws_proxy. 300 October 2013 Development and Extension Guide – Application-Specific Information * Call webservice proxy CALL METHOD lr_ws_proxy->refund_transaction EXPORTING input = ls_request IMPORTING output = ls_response. * Error handling CATCH cx_gdt_conversion cx_ai_system_fault cx_ai_application_fault INTO le_root. ls_message-type = 'E'. ls_message-message = le_root->if_message~get_text( ). CALL FUNCTION 'OWN_LOGICAL_SYSTEM_GET' IMPORTING own_logical_system = ls_message-system. APPEND ls_message TO et_messages. CLEAR ls_message. ev_success = abap_false. RETURN. ENDTRY. * Return the refund transaction ID ev_refund_trans_id = ls_response-refund_transaction_response-refund_transaction_id. * Handling of errors returned by PayPal CALL METHOD get_errors_from_paypal EXPORTING is_abstract_response_type = ls_response-refund_transaction_response-base iv_returned_value = ev_refund_trans_id IMPORTING et_messages = et_messages ev_success = ev_success. endmethod. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_COMMON_PAYPAL_API->SET_EXPRESS_CHECKOUT * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD set_express_checkout. DATA: lv_iso_langu TYPE laiso, lv_iso_currency TYPE tcurc-isocd, ls_request TYPE set_express_checkout_request, ls_response TYPE set_express_checkout_response1, ls_abstract_request_type TYPE abstract_request_type, ls_set_express_checkout_req TYPE set_express_checkout_request_1, lr_ws_proxy TYPE REF TO co_pay_pal_apiaainterface, October 2013 301 Development and Extension Guide – Application-Specific Information le_root TYPE REF TO cx_root, ls_message TYPE bapiret2. TRY. * Convert language key to ISO language code CALL METHOD cl_gdt_conversion=>language_code_outbound EXPORTING im_value = sy-langu IMPORTING ex_value = lv_iso_langu. * Convert currency key to ISO currency code CALL METHOD cl_gdt_conversion=>currency_code_outbound EXPORTING im_value = iv_currency IMPORTING ex_value = lv_iso_currency. * fill request data ls_abstract_request_type-error_language = lv_iso_langu. ls_abstract_request_type-version = gc_paypal_api_version. ls_set_express_checkout_req-order_total-currency_id = lv_iso_currency. ls_set_express_checkout_req-order_total-content = iv_amount. ls_set_express_checkout_req-return_url = iv_return_url. ls_set_express_checkout_req-cancel_url = iv_cancel_url. ls_set_express_checkout_req-invoice_id = iv_invoice_id. ls_set_express_checkout_req-custom = iv_custom. ls_request-set_express_checkout_request-base = ls_abstract_request_type. ls_request-set_express_checkout_request-set_express_checkout_request_d = ls_set_express_checkout_req. * Get webservice proxy CALL METHOD get_ws_interface EXPORTING iv_username = iv_username iv_password = iv_password iv_signature = iv_signature iv_logical_port = iv_logical_port IMPORTING er_interface = lr_ws_proxy. * Call webservice proxy CALL METHOD lr_ws_proxy->set_express_checkout EXPORTING input = ls_request IMPORTING output = ls_response. * Error handling CATCH cx_gdt_conversion cx_ai_system_fault cx_ai_application_fault INTO le_root. 302 October 2013 Development and Extension Guide – Application-Specific Information ls_message-type = 'E'. ls_message-message = le_root->if_message~get_text( ). CALL FUNCTION 'OWN_LOGICAL_SYSTEM_GET' IMPORTING own_logical_system = ls_message-system. APPEND ls_message TO et_messages. CLEAR ls_message. ev_success = abap_false. RETURN. ENDTRY. * Return the token ev_token = ls_response-set_express_checkout_response-token. * Handling of errors returned by PayPal CALL METHOD get_errors_from_paypal EXPORTING is_abstract_response_type = ls_response-set_express_checkout_response-base iv_returned_value = ev_token IMPORTING et_messages = et_messages ev_success = ev_success. ENDMETHOD. * <SIGNATURE>----------------------------------------------------------------------------------- ----+ * | Instance Private Method ZCL_COMMON_PAYPAL_API->TRANSACTION_SEARCH * +--------------------------------------------------------------------------------------------- ----+ * +-------------------------------------------------------------------------------------- </SIGNATURE> METHOD transaction_search. DATA: lv_iso_langu TYPE laiso, ls_request TYPE transaction_search_request, ls_response TYPE transaction_search_response, ls_abstract_request_type TYPE abstract_request_type, lr_ws_proxy TYPE REF TO co_pay_pal_apiinterface, le_root TYPE REF TO cx_root, ls_message TYPE bapiret2. FIELD-SYMBOLS: <ls_payment_transaction> TYPE payment_transactions. TRY. * Convert language key to ISO language code CALL METHOD cl_gdt_conversion=>language_code_outbound EXPORTING October 2013 303 Development and Extension Guide – Application-Specific Information im_value = sy-langu IMPORTING ex_value = lv_iso_langu. * Fill request data ls_abstract_request_type-error_language = lv_iso_langu. ls_abstract_request_type-version = gc_paypal_api_version. ls_request-transaction_search_request-base = ls_abstract_request_type. ls_request-transaction_search_request-start_date = iv_start_date. ls_request-transaction_search_request-end_date = iv_end_date. ls_request-transaction_search_request-transaction_id = iv_transaction_id. ls_request-transaction_search_request-invoice_id = iv_invoice_id. ls_request-transaction_search_request-amount-currency_id = iv_currency. ls_request-transaction_search_request-amount-content = iv_amount. * Get webservice proxy CALL METHOD get_ws_interface_for_trans EXPORTING iv_username = iv_username iv_password = iv_password iv_signature = iv_signature iv_logical_port = iv_logical_port IMPORTING er_interface = lr_ws_proxy. * Call webservice proxy CALL METHOD lr_ws_proxy->transaction_search EXPORTING input = ls_request IMPORTING output = ls_response. * Error handling CATCH cx_gdt_conversion cx_ai_system_fault cx_ai_application_fault INTO le_root. ls_message-type = 'E'. ls_message-message = le_root->if_message~get_text( ). CALL FUNCTION 'OWN_LOGICAL_SYSTEM_GET' IMPORTING own_logical_system = ls_message-system. APPEND ls_message TO et_messages. CLEAR ls_message. ev_success = abap_false. RETURN. ENDTRY. * Return found transactions LOOP AT ls_response-transaction_search_response-payment_transactions ASSIGNING <ls_payment_transaction>. APPEND <ls_payment_transaction>-transaction_id TO et_transaction_ids. 304 October 2013 Development and Extension Guide – Application-Specific Information ENDLOOP. * Handling of errors returned by PayPal CALL METHOD get_errors_from_paypal EXPORTING is_abstract_response_type = ls_response-transaction_search_response-base iv_returned_value = et_transaction_ids IMPORTING et_messages = et_messages ev_success = ev_success. ENDMETHOD. ENDCLASS. Note In many countries, legal regulations apply if you transfer personal data to a third party. To comply with these regulations, you might need to implement additional measures not included in this document that are not directly releated to communication with the payment service provider (for example, a logging mechanism to trace which data is transferred, to whom, and for what purpose). October 2013 305 Development and Extension Guide – Application-Specific Information 6.1.5 Order-Related SAP CRM Billing In order-related SAP CRM billing, order management and billing is completed in the SAP CRM back end. Only financials is completed in the SAP ERP back end. We recommend this scenario when no order fulfillment components are required (for example, when selling digital services like software by download). In the order-related SAP CRM billing scenario, configuration and the implementation of BAdI Integrate Payment Service Providers must be completed in the SAP CRM back end. You must implement BAdI Import Settlement Files for Each Payment Service Provider in the SAP ERP back end. The sales order in the SAP CRM back end gets status information from the payment service provider by way of the payment service provider interface (PSP IF). The sales order in the SAP CRM back end passes the payment service provider information by way of the CRM billing engine application to financials in the SAP ERP back end for settlement. 306 October 2013 Development and Extension Guide – Application-Specific Information Consider the following activities when using the order-related CRM billing scenario. 1. Activate business function in the SAP CRM back end. Activate the business function CRM_WEB_CHANNEL. 2. Maintain Customizing for PSP integration in the SAP CRM back end. Make the settings in Customizing for SAP CRM under Customer Relationship Management -> SAP Web Channel Experience Management -> E-Commerce -> Payment Service Providers. Note The first setting Download Payment … is not required. 3. Implement BAdI Integration of Payment Service Providers in the SAP CRM back end. For more information, see Sample Implementation of BAdI 'Integration of Payment Service Providers' in the SAP CRM Back End. 4. Configure CRM billing to process transactions involving payment service providers. Activate the Processing Transactions Involving PSPs feature in the CRMB application in Customizing for Customer Relationship Management under Billing -> Configure Application. 5. Implement BAdI Import Settlement Files for Each Payment Service Provider. For more information, see Sample Implementation of BAdI 'Import Settlement Files for Each Payment Service Provider'. 6. Schedule periodic tasks in the SAP CRM back end. Use the program Process Incomplete Payment Service Provider Orders (transaction CRMD_WEC_PSP_ORDER) to identify and process incomplete sales orders and service orders in the SAP CRM back end that Web shop customers create using payment service providers. For more information, see the online documentation for the program. October 2013 307 Development and Extension Guide – Application-Specific Information 6.1.6 Delivery-Related SAP CRM Billing In delivery-related CRM billing, order management and billing is completed in the SAP CRM back end. Order fulfillment and financials is completed in the SAP ERP back end. In the delivery-related CRM billing scenario, configuration and implementation of BAdI Integrate Payment Service Provider must be completed in the SAP CRM back end. You must implement BAdI Import Settlement Files for Each Payment Service Provider in the SAP ERP back end. The sales order in the SAP CRM back end gets status information from the payment service provider by way of the payment service provider interface (PSP IF). The sales order including its PSP status information is replicated to the SAP ERP back end. In SAP ERP, logistics execution is processed. Delivery in SAP ERP indicates fulfillment to the CRM billing engine application in the SAP CRM back end. The sales order in the SAP CRM back end passes the payment service provider information by way of the CRM billing engine to financials for settlement. 308 October 2013 Development and Extension Guide – Application-Specific Information Consider the activities in the following sections when using the delivery-related SAP CRM billing scenario. 1. Activate business function in the SAP ERP back end. Activate the ERP_WEB_CHANNEL_1 business function. 2. Maintain Customizing for PSP integration in the SAP ERP back end. Make the settings in Customizing for SAP ERP under Sales and Distribution -> SAP Web Channel Experience Management -> Payment Service Prov. 3. Activate business function in the SAP CRM back end. Activate the CRM_WEB_CHANNEL business function. 4. Maintain Customizing for payment service provider integration in the SAP CRM back end. Make the settings in Customizing for SAP CRM under Customer Relationship Management -> SAP Web Channel Experience Management -> E-Commerce -> Payment Service Providers. 5. Implement BAdI Integration of Payment Service Providers in the SAP CRM back end. For more information, see Sample Implementation of BAdI 'Integration of Payment Service Providers' in the SAP CRM Back End. 6. Configure the CRM billing engine application to process transactions involving payment service providers. Activate the Processing Transactions Involving PSPs feature in the CRM billing engine application (CRMB) in Customizing for SAP CRM under Customer Relationship Management -> Billing -> Configure Application. 7. Implement BAdI Import Settlement Files for Each Payment Service Provider. For more information, see Sample Implementation of BAdI 'Import Settlement Files for Each Payment Service Provider'. 8. Schedule periodic tasks in the SAP CRM back end. Use the program Process Incomplete Payment Service Provider Orders (transaction CRMD_WEC_PSP_ORDER) to identify and process incomplete sales orders and service orders in the SAP CRM back end that Web shop customers create using payment service providers. For more information, see the online documentation for the program. October 2013 309 Development and Extension Guide – Application-Specific Information 6.1.7 Extension Points 6.1.7.1 Passing Custom or Additional Attributes to the Payment Service Provider Interface To pass additional attributes to the payment service provider interface (PSP IF), you must redefine the PaymentServiceProviderConnectorImpl class of the module wec/ecom/mc/salestransactions/bo. The corresponding interface contains the two template methods for this purpose: mapToProcessInitiatePaymentServiceAPIExtension and mapToProcessCallbackPaymentServiceAPIExtension. The following code is an example: public List<NameValueParameter> mapToProcessInitiatePaymentServiceAPIExtension(Order order){ List<NameValueParameter> parameterListIn = new ArrayList<NameValueParameter>(); String netValueWOFreight = ConversionHelper.convertBigDecimalToStringABAPCommercialNotation(order.getNetValueWOFreight()); parameterListIn.add(new NameValueParameter ("netValueWOFreight", netValueWOFreight)); } 6.1.7.2 Embedding Icons for the Payment Service Provider on the User Interface Some payment service providers explicitly require Web shop owners to embed icons or graphics on the user interfaces of Web shops. Icons also enable Web shop owners to emphasize the payment services offered (for example, to gain attention). In order to embed icons or graphics, you can extend the following views: paymentServiceProviderDetailsCheckoutView.xhtml in module wec/comm/mc/payment/ui This view is used in the checkout process and it contains a list of configured payment services that can be selected for Web shop orders. paymentServiceProviderCheckoutCollapsedView.xhtml in module wec/comm/mc/payment/ui This view displays the selected payment service during checkout (while the checkout step is collapsed). You can also create a new view which contains all icons of all payment services (also credit cards, if applicable). You must then include this new view into one of the view areas of your basic pages (for example, in the right hand column of your home page or the checkout page). 310 October 2013 Development and Extension Guide – Application-Specific Information 6.2 Payment Card Authorization (SAP CRM) When Web shop customers save orders, the system executes the standard payment card authorization check in the SAP CRM back end. Note that if authorizations fail or only partially cover transaction amounts, Web shop customers can still save orders. Therefore, depending on your business scenario, you may want to prevent Web shop customers from submitting and saving orders when transaction amounts are not fully authorized by implementing the PREPARE method in Customizing for SAP CRM under Customer Relationship Management -> Transactions -> Basic Settings -> Business Add-Ins -> BAdI: Transfer Customer-Specific Fields to Middleware. The system calls the method after authorization and can abort the save with the DO_NOT_SAVE exception. The example implementation CRM_WEC_PAY_ORD_AUTH shows how to perform such a check. Caution The example implementation is for reference only and may not suit your business needs in a productive environment. October 2013 311 Development and Extension Guide – Application-Specific Information 6.3 Integration of E-Payment Processing Service for Credit Card Tokenization Integrating an e-payment processing service into SAP Web Channel Experience Management (WCEM) allows you to support your preferred secure e-payment provider (SEPP) in your Web shops. This example shows the steps necessary for enabling credit card number tokenization with a third-party SEPP. With credit card number tokenization, the issue of PCI compliance is outsourced to the provider since no credit card numbers reach the SAP CRM or SAP ERP back-end system. Note that in the SAP CRM or SAP ERP system, credit card tokenization needs to be active. The example only covers the main aspects of the Java UI side. 1. Extend the payment module. The view in which the Web shop customer enters the credit card data is replaced by the corresponding view provided by the payment provider. The view delivered by SAP can be found in the payment module, which is why this module has to be extended. Suppose the extension namespace is cust. metadata.xml: <?xml version="1.0" encoding="UTF-8"?> <module xmlns="http://www.sap.com/wec/frw/tc/modules/metadata" lazyLoad="true" mainModule="false" moduleID="payment"> <moduleType>application</moduleType> <configForModule>payment</configForModule> <config-file namespace="cust" part="ui" type="ui-repository">ui-repository.xml</config- file> </module> ui-repository.xml: <UIRepository xmlns="http://www.sap.com/wec/frw/tc/ui/runtime/ui-repository" module="payment"> <ViewComponent name="paymentCCardCheckoutView" componentHandlerClassName="com.cust.wec.app.common.module.payment.ui.handler.CustPa ymentCCardCheckoutViewHandler" /> </UIRepository> The custom view needs to be placed into META-INF/resources/cust/payment/components. 2. Provide the implementation of the view paymentCCardCheckoutView in order to reflect how the SEPP handles the input of credit cards. The SEPP provides the HTML view for entering the credit card data. This service, which can for example be JavaScript (JS) based, is called from the view handler CustPaymentCCardCheckoutViewHandler and exposes the results to the view. CustPaymentCCardCheckoutViewHandler needs to fulfill 2 tasks: Providing the script coding to the view that loads the credit card form from the SEPP, and providing the methods to attach a new credit card to the order, including the credit card attributes such as validity, issuer, CVV, and the tokenized credit card number. Triggering this view handler method can be done from the JS coding on the view. An important aspect of the integration is to make sure that it handles AJAX requests (toggling between the payment methods Invoice - Credit Cards - Cash On Delivery is done using AJAX). Based on the credit card data entered by the Web shop customer, a token is generated by the SEPP. This token, the credit card type, and the expiration date are handed over to the SAP CRM back end. This way, user-sensitive data such as the credit card number are not stored in the SAP CRM back end, but are handled by the SEPP. 3. Encapsulate other payment-relevant options such as gift cards, promotion codes, or loyalty points in a new step in checkout. A change in the checkout process configuration is needed in order to separate the payment methods from the 312 October 2013 Development and Extension Guide – Application-Specific Information other payment-relevant options. This is needed since the payment through the SEPP authorizes and generates the token first. Only when this is done can the sales transaction be updated. <Step UITitle="checkout.ui.step.paymentDetails.uititle" ID="S_PAY01" Description="Payment Details" STEPGROUP_ID="SG_DETAILS"> <StepElementRef UITitle="checkout.ui.stepelement.promotionCode.uititle" ID="SE_PAY04" Description="Promotions and Campaigns" showOnOrderConfirm="true"/> <StepElementRef UITitle="checkout.ui.stepelement.loyalty.uititle" ID="SE_LOY01" Description="Loyalty" showOnOrderConfirm="true"/> <StepElementRef UITitle="checkout.ui.stepelement.giftCard.uititle" ID="SE_GC01" Description="" showOnOrderConfirm="true"/> </Step> <Step UITitle="checkout.ui.step.paymentDetails.uititle" ID="S_PAY02" Description="Payment Details II" STEPGROUP_ID="SG_DETAILS"> <StepElementRef UITitle="checkout.ui.stepelement.paymentMethods.uititle" ID="SE_PAY01" Description="Payment Methods" showOnOrderConfirm="true"/> </Step> 4. Take care of the following issues: Reading of the credit card data from the SEPP in order to display the data in a consistent and user- friendly way in the collapsed and expanded step in checkout and in the order confirmation, in case the Web shop customer wants to change the previously entered credit card data The SEPP process is a 2-step mechanism: The SEPP has to be contacted first, then the token is sent to the back end. Each checkout step has a Continue button; this button should be hidden or disabled until the payment step data is ready to be sent to the SAP CRM back end. October 2013 313 Development and Extension Guide – Application-Specific Information 7 Web Services 7.1 Web Service Entity "Companies" Web service entity Companies supports the Web service framework functionality for extensions. This allows you to store and retrieve additional data without making enhancements in the Java code (see also the Development and Extension Guide: Generic Information for SAP Web Channel Experience Management on SAP Service Marketplace at http://service.sap.com/wec-inst, section Web Service Extension Handling). The following example shows how to retrieve the additional field DUNS-NUMBER for a SAP CRM back end. The recommended test environment is Mozilla Firefox, with the plug-in RESTClient being installed. The corresponding ABAP object is CRM_WEC_BP_GET_CONT_AND_COMP. Parameter Value METHOD GET URL https://<your_server>:<port>/main/odata/appid/<appID>/Companies(‘<companyID’)?$expand=Extens ions HTTP Add to Request Header: Headers Name: Content-Type Value: application/atom+xml;charset=iso-8859-1 Basic Authentication: <user> / <password> HTTP <?xml version='1.0' encoding='utf-8'?> Response <entry ... <m:inline> <feed> ... <content type="application/xml"> <m:properties> <d:Parent>Companies</d:Parent> <d:ParentKeys>'600673'</d:ParentKeys> <d:PropertyName>DUNS</d:PropertyName> <d:StringValue>76-982-0861</d:StringValue> </m:properties> </content> </entry> <entry> <category term="SAP_WEC.Companies" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/> <content type="application/xml"> <m:properties> <d:City>Chicago</d:City> ... </content> </entry> 314 October 2013 Development and Extension Guide – Application-Specific Information Required ABAP adaptations: Function module CRM_WEC_BP_GET_CONT_AND_COMP: Use an implicit enhancement point at the end of the function module. data: LT_IDENTDETAIL type table of BAPIBUS1006_ID_DETAILS, LS_IDENTDETAIL type BAPIBUS1006_ID_DETAILS, LS_EXTENSION_OUT type CRMT_ISALES_EXTENSION_INT, LV_COMPANY_GUID type BU_PARTNER_GUID. call function 'BUPA_IDENTIFICATIONDETAILS_GET' exporting IV_PARTNER = IV_COMPANY_ID tables ET_IDENTIFICATIONDETAIL = LT_IDENTDETAIL. read table LT_IDENTDETAIL into LS_IDENTDETAIL with key IDENTIFICATIONTYPE = 'BUP001'. "DUNS * Create extension entries in case DUNS is maintained if SY-SUBRC = 0. call function 'BUPA_NUMBERS_READ' exporting IV_PARTNER = IV_COMPANY_ID importing EV_PARTNER_GUID = LV_COMPANY_GUID. * Set ref_guid to separate extension entries for company and contact entity LS_EXTENSION_OUT-REF_GUID = LV_COMPANY_GUID. LS_EXTENSION_OUT-NAME = 'DUNS'. LS_EXTENSION_OUT-VALUE = LS_IDENTDETAIL-IDENTIFICATIONNUMBER. append LS_EXTENSION_OUT to ET_EXTENSION_OUT. endif. October 2013 315 Development and Extension Guide – Application-Specific Information 7.2 Web Service Entity "Consumer" Web service entity Consumer supports the Web service framework functionality for extensions. This allows you to store and retrieve additional data without making enhancements in the Java code (see also the Development and Extension Guide: Generic Information for SAP Web Channel Experience Management on SAP Service Marketplace at http://service.sap.com/wec-inst, section Web Service Extension Handling). The following example shows how to store and retrieve the additional fields BUILDING, FLOOR, and ROOM_NO for a SAP CRM back end. For this example, we use the advantage that the ABAP structure of the underlying function module already contains these fields. While simply setting these fields, this will be sufficient for the write process, but other fields that are not yet in the structure might require more enhancements in the system - these are not included in this example. The recommended test environment is Mozilla Firefox, with the plug-in RESTClient being installed. The corresponding ABAP objects are: CRM_WEC_REGISTER_CONSUMER CRM_WEC_GET_BP_CONSUMER_DETAIL CRM_WEC_IUSER_CHANGE 7.2.1 Registration Request via Web Service Consumer Parameter Value METHOD POST URL https://<your_server>:<port>/main/odata/appid/<appID>/Consumers HTTP Add to Request Header: Headers Name: Content-Type Value: application/atom+xml;charset=iso-8859-1 Body <?xml version="1.0" encoding="UTF-8"?> Content <entry xmlns="http://www.w3.org/2005/Atom" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xml:base="http://<your server>:<port>/main/odata/appid/<appID>/"> <content type="application/xml"> <m:properties> <d:City>Chicago</d:City> <d:ConsumerID>temp</d:ConsumerID> <d:CountryCode>US</d:CountryCode> <d:DistrictCode>COOK</d:DistrictCode> <d:EmailAddress>john.doe@anycompany.com</d:EmailAddress> <d:FaxNumber>759293</d:FaxNumber> <d:FirstName>John</d:FirstName> <d:FormattedAddress></d:FormattedAddress> <d:FormattedName></d:FormattedName> <d:HouseNumber>644</d:HouseNumber> <d:LastName>Doe</d:LastName> <d:LogonID>johndoe4711</d:LogonID> <d:MiddleName></d:MiddleName> <d:MobileNumber>759292</d:MobileNumber> <d:Password>welcome1</d:Password> <d:PhoneNumber>759291</d:PhoneNumber> <d:PostalCode>60611-3017</d:PostalCode> <d:RegionCode>IL</d:RegionCode> <d:Street>North Lake Shore Drive</d:Street> <d:TitleCode>0002</d:TitleCode> </m:properties> 316 October 2013 Development and Extension Guide – Application-Specific Information </content> <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/wec_Extensions" type="application/atom+xml;type=feed" title="wec_Extensions" > <m:inline> <feed> <entry> <category term="SAP_WEC.wec_Extension" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/> <content type="application/xml"> <m:properties> <d:Parent>user_Consumers</d:Parent> <d:ParentKeys>ConsumerID=’temp’</d:ParentKeys> <d:PropertyName>BUILDING</d:PropertyName> <d:StringValue>LAK01</d:StringValue> </m:properties> </content> <category term="SAP_WEC.wec_Extension" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/> <content type="application/xml"> <m:properties> <d:Parent>user_Consumers</d:Parent> <d:ParentKeys>ConsumerID=’temp’</d:ParentKeys> <d:PropertyName>FLOOR</d:PropertyName> <d:StringValue>3</d:StringValue> </m:properties> </content> <category term="SAP_WEC.wec_Extension" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/> <content type="application/xml"> <m:properties> <d:Parent>user_Consumers</d:Parent> <d:ParentKeys>ConsumerID=’temp’</d:ParentKeys> <d:PropertyName>ROOM_NO</d:PropertyName> <d:StringValue>A.23</d:StringValue> </m:properties> </content> </entry> </feed> </m:inline> </link> </entry> October 2013 317 Development and Extension Guide – Application-Specific Information A screenshot should look like this: Required ABAP adaptations: Function module CRM_WEC_REGISTER_CONSUMER: Use an implicit enhancement point at the beginning of the function module. field-symbols: <LS_EXTENSION_IN> type CRMT_ISALES_EXTENSION_INT, <LS_ADDRESS> type CRMS_WEC_ADDRESS, <LV_VALUE_TO> type ANY. data: LV_FIELDNAME_TO(40) type C. * Read address entry (always 1) read table ADDRESSES assigning <LS_ADDRESS> index 1. * Modify extension entries loop at EXTENSION_IN assigning <LS_EXTENSION_IN>. 318 October 2013 Development and Extension Guide – Application-Specific Information * For security reason check on the specific fields to be moved if <LS_EXTENSION_IN>-NAME eq 'BUILDING' or <LS_EXTENSION_IN>-NAME eq 'ROOM_NO' or <LS_EXTENSION_IN>-NAME eq 'FLOOR'. concatenate '<ls_address>-' <LS_EXTENSION_IN>-NAME into LV_FIELDNAME_TO. assign (LV_FIELDNAME_TO) to <LV_VALUE_TO>. <LV_VALUE_TO> = <LS_EXTENSION_IN>-VALUE. endif. endloop. 7.2.2 Reading Data via Web Service Consumer Parameter Value METHOD GET URL https://<your_server>:<port>/main/odata/appid/<appID>/Consumers(‘<consumerID’)?$expand=Exten sions HTTP Add to Request Header: Headers Name: Content-Type Value: application/atom+xml;charset=iso-8859-1 Basic Authentication: <user> / <password> HTTP <?xml version='1.0' encoding='utf-8'?> Response <entry ... <m:inline> <feed> ... <content type="application/xml"> <m:properties> <d:Parent>Consumers</d:Parent> <d:ParentKeys>'7000084664'</d:ParentKeys> <d:PropertyName>BUILDING</d:PropertyName> <d:StringValue>LAK01</d:StringValue> </m:properties> </content> </entry> <entry> ... <content type="application/xml"> <m:properties> <d:Parent>Consumers</d:Parent> <d:ParentKeys>'7000084664'</d:ParentKeys> <d:PropertyName>ROOM_NO</d:PropertyName> <d:StringValue>A.23</d:StringValue> </m:properties> </content> </entry> <entry> ... <content type="application/xml"> <m:properties> <d:Parent>Consumers</d:Parent> <d:ParentKeys>'7000084664'</d:ParentKeys> <d:PropertyName>FLOOR</d:PropertyName> <d:StringValue>5</d:StringValue> </m:properties> October 2013 319 Development and Extension Guide – Application-Specific Information </content> </entry> </feed> </m:inline> </link> <category term="SAP_WEC.Consumer" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/> <content type="application/xml"> <m:properties> <d:City>Chicago</d:City> <d:ConsumerID>7000084664</d:ConsumerID> <d:CountryCode>US</d:CountryCode> <d:CountryDescription>USA</d:CountryDescription> <d:DistrictCode>COOK</d:DistrictCode> ... </content> </entry> Required ABAP adaptations: Function module CRM_WEC_GET_BP_CONSUMER_DETAIL: Use an implicit enhancement point at the end of the function module. data: LS_EXTENSION_OUT type CRMT_ISALES_EXTENSION_INT. * Read standard address as this is the address of Consumer entity * itself (all other addresses are AdditionalConsumerAddresses) read table ET_ADDRESSES_DATA into LS_ADDRESS_DATA with key STANDARDADDRESS = 'X'. * Create extension entry (no key required) LS_EXTENSION_OUT-NAME = 'BUILDING'. LS_EXTENSION_OUT-VALUE = LS_ADDRESS_DATA-BUILDING. append LS_EXTENSION_OUT to ET_EXTENSION_OUT. LS_EXTENSION_OUT-NAME = 'FLOOR'. LS_EXTENSION_OUT-VALUE = LS_ADDRESS_DATA-FLOOR. append LS_EXTENSION_OUT to ET_EXTENSION_OUT. LS_EXTENSION_OUT-NAME = 'ROOM_NO'. LS_EXTENSION_OUT-VALUE = LS_ADDRESS_DATA-ROOM_NO. append LS_EXTENSION_OUT to ET_EXTENSION_OUT. 7.2.3 Updating Data via Web Service Consumer Parameter Value METHOD PUT URL https://<your_server>:<port>/main/odata/appid/<appID>/Extensions(Parent='Consumers',ParentKeys=' ConsumerID=''7000084664''',PropertyName='FirstName') HTTP Add to Request Header: Headers Name: Content-Type Value: application/atom+xml;charset=iso-8859-1 <b>Basic Authentication: <user> / <password></b> Body <?xml version="1.0" encoding="UTF-8"?> Content <entry xmlns="http://www.w3.org/2005/Atom" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 320 October 2013 Development and Extension Guide – Application-Specific Information xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xml:base=" http://<your server>:<port>/main/odata/appid/<appID>/"> <category term="SAP_WEC.wec_Extension" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/> <content type="application/xml"> <m:properties> <d:Parent>user_Consumers</d:Parent> <d:ParentKeys>ConsumerID='7000084664'</d:ParentKeys> <d:PropertyName>ROOM_NO</d:PropertyName> <d:StringValue>A.25</d:StringValue> </m:properties> </content> </entry> Required ABAP adaptations: Function module CRM_WEC_IUSER_CHANGE: Use an implicit enhancement point at the beginning of the function module. field-symbols: <LS_EXTENSION_IN> type CRMT_ISALES_EXTENSION_INT, <LS_ADDRESS> type CRMS_WEC_ADDRESS, <LS_ADDRESS_X> type CRMS_WEC_ADDRESS_X. * Read standard address as this is the address of Consumer entity * itself (all other addresses are AdditionalConsumerAddresses) read table ADDRESSES assigning <LS_ADDRESS> with key STANDARDADDRESS = 'X'. read table ADDRESSES_X assigning <LS_ADDRESS_X> with key STANDARDADDRESS = 'X'. * Modify extension entries loop at EXTENSION_IN assigning <LS_EXTENSION_IN>. * For security reason check on the specific fields to be moved if <LS_EXTENSION_IN>-NAME eq 'BUILDING'. <LS_ADDRESS>-BUILDING = <LS_EXTENSION_IN>-VALUE. <LS_ADDRESS_X>-BUILDING = 'X'. endif. if <LS_EXTENSION_IN>-NAME eq 'ROOM_NO'. <LS_ADDRESS>-ROOM_NO = <LS_EXTENSION_IN>-VALUE. <LS_ADDRESS_X>-ROOM_NO = 'X'. endif. if <LS_EXTENSION_IN>-NAME eq 'FLOOR'. <LS_ADDRESS>-FLOOR = <LS_EXTENSION_IN>-VALUE. <LS_ADDRESS_X>-FLOOR = 'X'. endif. endloop. October 2013 321 Development and Extension Guide – Application-Specific Information 7.3 Web Service "SalesOrderItemScheduleLines" This example shows how you can extend the sales order Web services delivered by SAP, to get the schedule lines for each sales order item. The SalesOrderItems Web service will have a relation to the SalesOrderItemScheduleLines Web service and will be the root Web service for the schedule lines. The dependent Web service SalesOrderItemScheduleLines can be accessed via the navigation property of the root Web service. Note With this example, it is only possible to get the schedule lines while a sales order is being read (GET request). It is not possible to get the schedule lines in response of a POST request since the schedule lines are determined in the back end and cannot be created using an inline create request (deep create). 1. Create an extension module for the salestransactions module, including corresponding applications (for more information, , see the Development and Extension Guide: Generic Information for SAP Web Channel Experience Management on SAP Service Marketplace at http://service.sap.com/wec-inst, section Creating a Custom Web Site and Custom Web Channel Builder) and Web Channel Builder configuration. In this example, it is sufficient to create an md and ws development component (DC). For more information about Web Channel Builder, see the section on Web Channel Builder modules in this guide. You can also see SAP Library for SAP Web Channel Experience Management on SAP Help Portal at http://help.sap.com/wec. Choose a release and then Application Help. In SAP Library, choose SAP Web Channel Experience Management -> Configuration -> Configuring Web Channel Applications (Web Channel Builder). The new DCs might look like this: 2. Add the following dependencies to the new ws DC: 322 October 2013 Development and Extension Guide – Application-Specific Information 3. Add the following dependencies to the new dpu DC: 4. Add the following dependencies to the new md DC: 5. Add the following content to the metadata.xml file of the created md part. This allows you to use the relation plug-in provided in the salestransactions module: metadata.xml <?xml version="1.0" encoding="UTF-8"?><?xml version="1.0" encoding="UTF-8"?> <module xmlns="http://www.sap.com/wec/frw/tc/modules/metadata" lazyLoad="true" mainModule="false" moduleID="salestransactions"> <moduleType>application</moduleType> <configForModule>salestransactions</configForModule> <config-file namespace="customer" part="ws" type="ws-config">ws-config.xml</config-file> <public-part> <interfaceImplementations> <!-- Interface for Sales Order Item Attributes relation plugin--> <interfaceImplementation interfaceName="com.sap.sales.SalesOrderItemAttributesRelationPlugIn"> <webServiceRelation webServiceName="SalesOrderItems" targetWebServiceName="SalesOrderItemSchedules" relationName="SalesOrderItemSchedules" cardinality="MANY" /> </interfaceImplementation> </interfaceImplementations> </public-part> </module> October 2013 323 Development and Extension Guide – Application-Specific Information 6. Specify your own namespace (here customer) in the module.properties file of both the md part and ws part. This could look like this: module.properties sap.com.moduleId=salestransactions sap.com.moduleNamespace=customer sap.com.extendsNamespace=sap sap.com.modulePart=ws 7. Define your own Web service for reading schedule lines in the ws-config-xml in the ws part: ws-config.xml <webServices xmlns="http://www.sap.com/wec/frw/tc/modules/metadata/webServices" xmlns:wec="com.sap.wec.core.config" xmlns:xi="http://www.w3.org/2001/XInclude"> <webService webServiceEntityName="SalesOrderItemSchedule" webServiceName="SalesOrderItemSchedules"> <serviceObject authRequired="true" beanClassName="com.customer.wec.app.esales.module.transaction.ws.beans.SalesOrderItemSched uleLineSOBean" handlerClassName="com.customer.wec.app.esales.module.transaction.ws.handler.SalesOrderItem ScheduleLineSOHandler"/> </webService> </webServices> 8. Create your own service object bean in your ws DC to define the metadata of the newly created Web service: SalesOrderItemScheduleLineSOBean.java 324 October 2013 Development and Extension Guide – Application-Specific Information package com.customer.wec.app.esales.module.transaction.ws.beans; import java.math.BigDecimal;import java.util.Date;package com.customer.wec.app.esales.module.transaction.ws.beans; import java.math.BigDecimal; import java.util.Date; import javax.xml.bind.annotation.XmlRootElement; import com.sap.wec.tc.core.webservices.metadata.annotation.ServiceBean; import com.sap.wec.tc.core.webservices.metadata.annotation.ServiceProperty; import com.sap.wec.tc.core.webservices.so.ServiceObjectBeanBase; @XmlRootElement(name = "SalesOrderItemSchedule") @ServiceBean(rootNode = false, shortDescription = "Sales Order Item Schedule Lines") public class SalesOrderItemScheduleLineSOBean extends ServiceObjectBeanBase { private String salesOrderKey; private int itemNumber; private int scheduleNumber; private BigDecimal confirmedQuantity; private Date confirmedDate; @ServiceProperty(key = true, shortDescription = "Sales Order Key Field", readonly = true, creatable = false) public String getSalesOrderKey() { return salesOrderKey; } public void setSalesOrderKey(String salesOrderKey) { this.salesOrderKey = salesOrderKey; } @ServiceProperty(readonly = true, key = true, shortDescription = "Sales Order Item Key Field)", creatable = false) public int getItemNumber() { return itemNumber; } public void setItemNumber(int itemNumber) { this.itemNumber = itemNumber; } @ServiceProperty(readonly = true, key = true, shortDescription = "Schedule Item (Key Field)", creatable = false) public int getScheduleNumber() { return scheduleNumber; } public void setScheduleNumber(int scheduleNumber) { this.scheduleNumber = scheduleNumber; } @ServiceProperty(readonly = true, creatable = false) public BigDecimal getConfirmedQuantity() { October 2013 325 Development and Extension Guide – Application-Specific Information return confirmedQuantity; } public void setConfirmedQuantity(BigDecimal confirmedQuantity) { this.confirmedQuantity = confirmedQuantity; } @ServiceProperty(readonly = true, creatable = false) public Date getConfirmedDate() { return confirmedDate; } public void setConfirmedDate(Date confirmedDate) { this.confirmedDate = confirmedDate; } } 9. Create your own service object handler in your ws DC to manage the newly created Web service: SalesOrderItemScheduleLineSOHandler package com.customer.wec.app.esales.module.transaction.ws.handler; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; import com.customer.wec.app.esales.module.transaction.ws.beans.SalesOrderItemScheduleLineSOBean; import com.sap.wec.app.common.module.transaction.businessobject.interf.Schedline; import com.sap.wec.app.common.module.transaction.item.businessobject.interf.Item; import com.sap.wec.app.common.module.transaction.item.businessobject.interf.ItemList; import com.sap.wec.app.esales.module.transaction.businessobject.interf.Order; import com.sap.wec.app.esales.module.transaction.ws.beans.SalesOrderItemSOBean; import com.sap.wec.app.esales.module.transaction.ws.handler.SalesOrderDependentObjectSOHandler; import com.sap.wec.app.esales.module.transaction.ws.util.ExceptionMessageTexts; import com.sap.wec.tc.core.webservices.so.ServiceObjectKey; import com.sap.wec.tc.core.webservices.so.ServiceObjectRelation; import com.sap.wec.tc.core.webservices.so.exception.ServiceApplicationProcessingException; import com.sap.wec.tc.core.webservices.so.exception.ServiceBadRequestException; import com.sap.wec.tc.core.webservices.so.request.ServiceRelationRequest; import com.sap.wec.tc.core.webservices.so.request.ServiceRequestContext; import com.sap.wec.tc.core.webservices.so.request.ServiceRetrieveRequest; import com.sap.wec.tc.core.webservices.so.request.ServiceRetrieveRequest.RetrieveType; public class SalesOrderItemScheduleLineSOHandler extends SalesOrderDependentObjectSOHandler { @Override 326 October 2013 Development and Extension Guide – Application-Specific Information public List<SalesOrderItemScheduleLineSOBean> getObjects(ServiceRetrieveRequest retrieveRequest) throws ServiceApplicationProcessingException { checkRetrieveType(retrieveRequest); getOrder(orderKeyFromRequest(retrieveRequest)); List<SalesOrderItemScheduleLineSOBean> result = new ArrayList<SalesOrderItemScheduleLineSOBean>(); for (ServiceObjectKey key : retrieveRequest.getKeyList()) { Item item = getItem(order, key); List<Schedline> scheduleLines = item.getScheduleLines(); int scheduleLinesNumber = 1; for (Schedline schedline : scheduleLines) { SalesOrderItemScheduleLineSOBean bean = (SalesOrderItemScheduleLineSOBean) createServiceObjectBean(); bean.setSalesOrderKey(order.getTechKey().getIdAsString()); bean.setItemNumber(item.getNumberInt()); bean.setScheduleNumber(scheduleLinesNumber); bean.setConfirmedDate(schedline.getCommittedDate()); bean.setConfirmedQuantity(schedline.getCommittedQuantity()); result.add(bean); scheduleLinesNumber++; } } return result; } public ServiceObjectRelation getRelation(ServiceRelationRequest relationRequest) throws ServiceApplicationProcessingException { ServiceObjectRelation relation = relationRequest.getRelation(); if ("SalesOrderItemSchedules".equals(relation.getRelationName())) { ServiceObjectKey sourceKey = relation.getSourceKey(); getOrder(helper.toOrderKey(sourceKey)); String orderKey = order.getTechKey().getIdAsString(); Item item = getItem(order, sourceKey); int scheduleLinesSize = item.getScheduleLines().size(); if (scheduleLinesSize > 0) { List<ServiceObjectKey> targetKeys = new ArrayList<ServiceObjectKey>(scheduleLinesSize); for (int i = 0; i < scheduleLinesSize; i++) { Map<String, Object> keyList = new TreeMap<String, Object>(); keyList.put("ScheduleNummber", i + 1); keyList.put("SalesOrderKey", orderKey); keyList.put("ItemNumber", Integer.valueOf(item.getNumberInt())); ServiceObjectKey targetKey = createServiceObjectKey(keyList); targetKeys.add(targetKey); } relation.setTargetKeys(targetKeys); } } return relation; } October 2013 327 Development and Extension Guide – Application-Specific Information private void checkRetrieveType(ServiceRetrieveRequest retrieveRequest) throws ServiceBadRequestException { if (retrieveRequest.getType() == RetrieveType.UNSPECIFIED) throw new ServiceBadRequestException(ExceptionMessageTexts.SALES_ORDER_ITEMS_ONLY_VIA_MULTI_READ); } @Override public Item getBOReference(ServiceObjectKey key, ServiceRequestContext requestContext) throws ServiceApplicationProcessingException { getOrder(helper.toOrderKey(key)); return getItem(order, key); } protected Item getItem(Order order, ServiceObjectKey key) throws ServiceApplicationProcessingException { Item result = null; Integer expectedKey = null; Object no = key.getComplexKeys().get(SalesOrderItemSOBean.SALES_ORDER_ITEM_NUMBER); expectedKey = no instanceof Integer ? (Integer) no : Integer.parseInt((String) no); result = getItemByKey(expectedKey); if (result == null) throw new ServiceApplicationProcessingException(ExceptionMessageTexts.ITEM_WITH_KEY_DOES_NOT_EXIST + expectedKey); return result; } private Item getItemByKey(Integer expectedKey) { Item result = null; ItemList itemList = order.getItemList(); for (Item item : itemList) { int number = item.getNumberInt(); if (expectedKey == number) { result = item; break; } } return result; } } 10. Add the source root folder for your chosen namespace (in this example, customer) to the assembly public part of the ui DC, as a Java package tree. Otherwise, the new class added might not be deployed on the server and an exception might occur since the class is not found. 328 October 2013 Development and Extension Guide – Application-Specific Information 11. Make sure you have the correct configuration within Web Channel Builder: 12. Activate the Web service for schedule lines in the Web Channel Builder configuration: October 2013 329 Development and Extension Guide – Application-Specific Information 13. Now your GET request will return the available schedule lines for the order items: 330 October 2013