Update contracts in CRM using BDCs
Some firms have an army of dedicated data entry personnel. For those who don't, LSMW can provide a solution that is fast and accurate, albeit somewhat complicated.
SAP's Customer Relationship Management (CRM) software is written in the same language as ECC and, in addition to the web-based interface, uses the same GUI interface as ECC for most operations.
Because CRM is written in ABAP and includes LSMW, it is possible to automate changes to documents using a BDC. Creating the BDC can be a little tricky, but one can create a simple recording to accomplish in minutes what might take an army of interns days or weeks.
The first thing to note is that the interface for selecting items in a Contract relies on double-clicking. This seldom works well in a recording, so the alternate method of selecting the item from a dropdown menu is used in this case.
Start a recording using the transaction CDRM_ORDER
. Open the contract to be modified and then select the item to be modified.
Change the program from Display to Change.
Make the changes and then save the recording. If multiple items on a single contract need to be modified then the program will create multiple entries in the BDC--one for each item.
Notice in the recording that there is a field labeled CRMT_7100_1O_UI-ITEM_GUID
in the recording now. This field is the drop-down menu and is populated with the GUID
of the line item from the Contract!
The GUID
field is 32 seemingly random characters that SAP uses to knit bits of data into a Contract. The contract is spread over dozens of tables that are linked directly or indirectly using CRMD_ORDER_INDEX
and CRMD_LINK
.
Finding the GUID of the item to populate this field is now the trickiest part of this exercise. It starts by locating the HEADER
using the Contract number in the CRMD_ORDERADM_H table. That value is used to find the ITEM
values from the CRMD_ORDER_INDEX
table.
- Contracts
- CRMD_ORDERADM_H-GUID → CRMD_ORDER_INDEX-HEADER
- CRMD_ORDER_INDEX-ITEM → CRMD_ORDERADM_I-GUID (This is CRM's internal number for the line item!)
- CRMD_ORDERADM_I-GUID → CRMD_LINK-GUID_HI
- CRMD_LINK-GUID_SET → CRMD_PRICING-GUID (Here is stored the pricing on the item!)
The ITEM values then point to records in CRMD_ORDERADM_I
table. This table contains the line items in the Contracts. Some line items are Ship-To pricing under a single sold to, so don't be frightened if the PARTNER
value in CRMD_ORDER_INDEX
points to different customers.
One more indirect link connects the items to the pricing for those items. The code below makes it a little easier to understand the relationship.
Start by declaring variables to hold data that is being read from the tables. CRM throws an error when attempting to join on GUID
fields, so the process is a little more cumbersome than it needs to be; nested selects are used instead of joins.
data: lCRMDOI like CRMD_ORDER_INDEX, lCRMDOAH like CRMD_ORDERADM_H, lCRMDOAI like CRMD_ORDERADM_I, lCRMDL like CRMD_LINK, lCRMDP like CRMD_PRICING.
Then stepping through the source data is the easy part. The code performs the actions above and validations can be performed to eliminate the risk of error. This snippet prepares to load a Pricing Group and skips the record if the Contract already has the correct Pricing Group.
select single * from CRMD_ORDERADM_H into lCRMDOAH where OBJECT_ID eq ORDERS-CONTRACT. if sy-subrc ne 0. write: / ORDERS-CONTRACT color col_negative, 'Invalid contract.'. skip_transaction. endif. select distinct HEADER ITEM from CRMD_ORDER_INDEX into corresponding fields of lCRMDOI where HEADER eq lCRMDOAH-GUID. select * from CRMD_ORDERADM_I into lCRMDOAI where GUID eq lCRMDOI-ITEM and NUMBER_INT eq ORDERS-NUMBER_INT. select * from CRMD_LINK into lCRMDL where GUID_HI eq lCRMDOAI-GUID and OBJTYPE_SET eq '09'. select * from CRMD_PRICING into lCRMDP where GUID eq lCRMDL-GUID_SET and PRICE_GRP eq ORDERS-PRICE_GROUP. write: / ORDERS-CONTRACT, ORDERS-NUMBER_INT, ORDERS-PRICE_GROUP color col_positive, 'Price group already up-to-date.'. skip_transaction. endselect. endselect. move lCRMDOAI-GUID to CRMD_ORDER-ITEM_GUID. endselect. endselect. if CRMD_ORDER-ITEM_GUID is initial. write: / ORDERS-CONTRACT, ORDERS-NUMBER_INT color col_negative, 'Invalid ITEM Number.'. skip_transaction. endif.
To wrap it up, throw in this snippet of code for the PRICE_GRP field. It validates that the Price Group to be loaded is valid.
select single PRICE_GROUP from CRMC_PRICEGRP into CRMD_ORDER-PRICE_GRP where PRICE_GROUP eq ORDERS-PRICE_GROUP. if sy-subrc ne 0. write: / ORDERS-CONTRACT, ORDERS-NUMBER_INT, ORDERS-PRICE_GROUP color col_negative, 'Invalid price group.'. skip_transaction. endif.
Note: On a system with a lot of legacy data this process can be slow. Don't fret--it's still much faster, accurate and reliable than having interns manually type it in.
Note: The BDC produced by this recording cannot be run in background mode. It can only run in "Foreground" or "Display errors only" mode because the program calls an interface that cannot run in background mode and throws a "GUI cannot be reached" error.
Note: If it seems like every other record in the batch fails to switch from Display to Change mode, it is because the system thinks that the transaction before is still processing. The CRM system does not report that the document is still open, but simply fails to enter change mode when the BDC attempts to use theBDC_OKCODE
"=10MAIN_TT".
If this is happening, then reordering the source data will work or adding this snippet of code to the PRICE_GRP line will prevent the same thing. It will skip subsequent lines on a contract after one line has been added to the BDC; this requires the program to be run enough times to catch all the lines in the longest contract in the source data.
**** Don't run updates back-to-back; it causes them not to **** switch to "edit mode", but stay in view mode instead. if lORDER eq ORDERS-CONTRACT. skip_transaction. else. lORDER = ORDERS-CONTRACT. endif.