The scenario that we are going to walk through
involves a Quoting system for an Energy company. Customers will engage
the Energy company to build infrastructure so that they can power their
plant/office/home/farm and so on. The Quoting system is built upon a
Dynamics CRM/XRM platform. As part of this quoting system, we need to be
able to factor in the amount our materials will cost us when providing a
quote to our customer. Some of SAP's strengths reside in Supply Chain
Management and Material Management so it makes sense to continue to
leverage this functionality in SAP. In our scenario, SAP is the system
of record for all Material Management. As the cost of materials
fluctuate over the course of a year, due to changes in commodity
markets, the average moving price will follow suit. We do not want to be
over-quoting or under-quoting our customer so we need to acquire the
moving average price for our materials before providing a quote to a
customer.
The RFC that we are going to use is called BAPI_MATERIAL_GET_DETAIL
and it is available out of the box. Wait a minute! I thought we were
discussing RFCs in this walkthrough, ao why does it start with "BAPI"? When generating schemas, it is a good practice to use the Filename Prefix. My personal preference is to use the name of the BAPI as the Filename Prefix; this way there is no confusion inside of Visual Studio.
Inside of Visual Studio, we will find two schemas generated called: BAPI_MATERIAL_GET_DETAILRfc.xsd and BAPI_MATERIAL_GET_DETAILTypes.xsd.
Inside the BAPI_MATERIAL_GET_DETAILRfc.xsd schema, we will discover that both request and response records exist. The BAPI_MATERIAL_GET_DETAILTypes.xsd schema simply contains the underlying SAP data types.
Next, we want to build a schema that our CRM system can populate. The name of this schema is called MaterialDetailRequest.xsd and it contains three elements. For simplicity purposes, all fields are of type string.
Field Name
|
Purpose
|
---|
MaterialID
|
The identifier used to distinguish different materials.
|
Plant
|
The location where goods are produced or provided from. In our situation, we would consider a warehouse a Plant.
|
ValuationArea
|
There are two types of Valuation Areas: Company and Plant. Since costs
may differ depending upon which plant they are coming from, it could
impact the price. Suppose you had a plant, or warehouse, in a remote
area. There may be additional transportation costs in retrieving a
particular material from that plant. Conversely, if you had a
centralized warehouse then you may want to use a Company level cost that
would be consistent across materials.
In our example, we are going to use Plant level and will provide the
Plant ID as our value in this Request message.
|
Note: it is a best practice to not expose your
system generated schemas to consuming clients. In the case of SAP, the
schemas that are generated are generally not user/developer friendly,
and we do not want to pass down that complexity to teams that may not be
as strong in system integration as a BizTalk or Middleware team. We
also do not want to have to manage client interfaces breaking should a
change to an SAP schema change. For instance, if we would have exposed
the old SAP adapter schemas to our client consuming systems and then
decided to upgrade the BizTalk interfaces to support the new WCF-SAP
adapter, we would have significant, unnecessary, changes to the client
application as well.
We now want to create a map called MaterialDetailRequestDisk_to_MaterialDetailRequestSAP.btm that will transform our MaterialDetailRequest into our BAPI_MATERIAL_GET_DETAIL request.
Next, we need to build a map that will transform the BAPI_MATERIAL_GET_DETAILResponse into a MaterialDetailResponse that we can send back to our calling CRM system. The map to do this is called MaterialDetailResponseSAP_to_MaterialDetailResponseDisk.btm. The nodes that are being mapped are as follows:
BAPI_MATERIAL_GET_DETAILResponse
|
MaterialDetailResponse
|
/MATERIAL_GENERAL_DATA/MATL_DESC
|
MaterialDescription
|
/MATERIAL_GENERAL_DATA/MATL_TYPE
|
MaterialType
|
/MATERIAL_GENERAL_DATA/BASE_UOM
|
UnitOfMeasure
|
/MATERIAL_GENERAL_DATA/NET_WEIGHT
|
NetWeight
|
/MATERIAL_GENERAL_DATA/CREATED_ON
|
MaterialCreateDate
|
/MATERIAL_GENERAL_DATA/LAST_CHNGE
|
MaterialLastUpdated
|
/MATERIALVALUATIONDATA/MOVING_PR
|
MovingPrice
|
/MATERIALVALUATIONDATA/PRICE_UNIT
|
PriceUnit
|
/MATERIALVALUATIONDATA/CURRENCY
|
Currency
|
In order to coordinate all of these events, an orchestration called ProcessGetMaterialDetails.odx is required. Inside this orchestration, the following events take place: We receive an instance of the Material Detail Request. Transform the Material Detail Request into a SAP BAPI_MATERIAL_GET_DETAIL Request. Send the BAPI_MATERIAL_GET_DETAIL Request to SAP and receive the BAPI_MATERIAL_GET_DETAIL Response. Transform the BAPI_MATERIAL_GET_DETAIL Response into a Material Detail Response. Send the Material Detail Response back to the calling application.
With our signed key in place. Once inside the BizTalk Administration console. We need to create a Receive Port called ReceiveMaterialDetailRequest that has a Receive Location called ReceiveMaterialDetailRequestFromDisk. This receive location will use the FILE Adapter, the BizTalkServerApplication Receive handler, and the XMLReceive Receive pipeline.
Two Send Ports are required for this solution. The first one that we want to address is the SAP two-way send port called SendMaterialDetailRequestToSAP. This Send Port will use the WCF-SAP adapter, the BizTalkServerApplication Send handler, the XMLTransmit Send pipeline, and the XMLReceive Receive pipeline.
Click on the Configure button to edit the SAP-specific properties. Click the Configure button again to edit the SAP URI. If you are unsure of the values for your organization, please contact your BASIS administrator.
Click the OK button to close this dialog. Our SOAP Action Header's Action
value must match the name of the logical operation that we provided
within our Orchestration. With this said, we need to provide the
following Action within our Send Port. <BtsActionMappingxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Operation Name="Operation_SendMaterialDetailRequestToSAP" Action="http://Microsoft.LobServices.Sap/2007/03/Rfc/BAPI_MATERIAL_GET_DETAIL" />
</BtsActionMapping>
In the Binding tab, I want to highlight two properties: EnableBizTalkCompatibilityMode — This value should always be set to True when calling SAP operations from BizTalk. EnableSafeTyping
— Since not all .NET and SAP types are created equally, we occasionally
need to loosen some constraints around dates. For example, if optional
dates are being returned from an RFC/BAPI, we may experience the
following error: Microsoft.ServiceModel.Channels.Common.XmlReaderGenerationException:
An error occurred when trying to convert the byte array
[30-00-30-00-30-00-30-00-30-00-30-00-30-00-30-00] of RFCTYPE
RFCTYPE_DATE with length 8 and decimals 0 to XML format. To work around this, we can set the EnableSafeTyping property to True. By doing so, the WCF-SAP adapter will expose SAP DATS values as strings instead of DateTime.
On the Credentials tab, we need to provide our SAP credentials. In this scenario, we are using Username/Password credentials.
The
next Send port that we address will send our Material Detail Response to
disk where it can be consumed by the calling application. The name of
this Send port is SendMaterialDetailsResponseToDisk. The Send port will use the FILE Adapter, BizTalkServerApplication Send handler and the PassThruTranmit Send pipeline.
In order to start our application, we must bind our orchestration to the Physical Receive and Send ports that we just created.
|