Skip to Content
Technical Articles
Author's profile photo Scar Ai

Export product catalog from SAP Commerce Cloud to procurement system for Punchout level 2

Background

Hello All,

SAP Commerce Cloud in the Public Cloud(I’ll use Commerce for short name in this article) will support punchout level 2 with release 2211. As one of the prerequisites,  we have to upload product catalog information to procurement system. Below we provide a solution to automatically upload product catalog from Commerce to procurement system.

Prerequisites

  • You are the back office admin of Commerce
  • You have right to deploy new iFlow in SAP Cloud integration 
  • You have admin right to import impex file in Commerce HAC(optional)

 

Design

As commerce cloud has OOTB Integrations and Data Management to export product info and changes to external terminal. We just tries to:

Below is a rough overall view of what’s we have done

overall%20view%20of%20our%20solution

 

 

Setup in Commerce cloud

In order to export product data from SAP Commerce Cloud to external system, firstly a new product integration object should be created, and then configure consumed destination and outbound sync.

1. Create the Product Integration Object

Create an Integration Object, for example, PunchoutProduct, that contains the code, name, catalogVersion and other required attributes. You can create the object using ImpEx.

  1. In a web browser, navigate to the SAP Commerce Cloud Administration Console at https://localhost:9002/ and log in.
  2. Click Console > ImpEx Import
  3. Paste the ImpEx into the Import Content field and click Import content, which will export product info with virtualProductCode as product-<product-code>
    Sample ImpEx:

    INSERT_UPDATE Script; code[unique = true]; content                           ; active[default = true, unique = true]
                        ; virtualProductCode        ; "import de.hybris.platform.core.model.product.ProductModel;
    ProductModel product = (ProductModel)itemModel;
    return ""product-""+product.code" ; true
    
    # Configure Integration Object
    INSERT_UPDATE IntegrationObject; code[unique = true]; integrationType(code)
                                   ; PunchoutProduct    ; INBOUND
    
    INSERT_UPDATE IntegrationObjectItem; integrationObject(code)[unique = true]; code[unique = true]; type(code)     ; root[default = false]; itemTypeMatch(code)
                                       ; PunchoutProduct                       ; Product            ; Product        ; true                 ; ALL_SUB_AND_SUPER_TYPES ;
                                       ; PunchoutProduct                       ; PriceRow           ; PriceRow       ;                      ; ALL_SUB_AND_SUPER_TYPES ;
                                       ; PunchoutProduct                       ; Currency           ; Currency       ;                      ; ALL_SUB_AND_SUPER_TYPES ;
                                       ; PunchoutProduct                       ; Catalog            ; Catalog        ;                      ; ALL_SUB_AND_SUPER_TYPES ;
                                       ; PunchoutProduct                       ; CatalogVersion     ; CatalogVersion ;                      ; ALL_SUB_AND_SUPER_TYPES ;
    
    INSERT_UPDATE IntegrationObjectItemAttribute; integrationObjectItem(integrationObject(code), code)[unique = true]; attributeName[unique = true]; attributeDescriptor(enclosingType(code), qualifier); returnIntegrationObjectItem(integrationObject(code), code); unique[default = false]; autoCreate[default = false]
                                                ; PunchoutProduct:Product                                            ; catalogVersion              ; Product:catalogVersion                             ; PunchoutProduct:CatalogVersion                            ; true                   ;
                                                ; PunchoutProduct:Product                                            ; manufacturerAID             ; Product:manufacturerAID                            ;                                                           ;                        ;
                                                ; PunchoutProduct:Product                                            ; unspcs                      ; Product:unspcs                                     ;                                                           ;                        ;
                                                ; PunchoutProduct:Product                                            ; europe1Prices               ; Product:europe1Prices                              ; PunchoutProduct:PriceRow                                  ;                        ;
                                                ; PunchoutProduct:Product                                            ; description                 ; Product:description                                ;                                                           ;                        ;
                                                ; PunchoutProduct:Product                                            ; unitOfMeasure               ; Product:unitOfMeasure                              ;                                                           ;                        ;
                                                ; PunchoutProduct:Product                                            ; manufacturerName            ; Product:manufacturerName                           ;                                                           ;                        ;
                                                ; PunchoutProduct:Product                                            ; name                        ; Product:name                                       ;                                                           ;                        ;
                                                ; PunchoutProduct:Product                                            ; code                        ; Product:code                                       ;                                                           ; true                   ;
                                                ; PunchoutProduct:PriceRow                                           ; currency                    ; PriceRow:currency                                  ; PunchoutProduct:Currency                                  ; true                   ;
                                                ; PunchoutProduct:PriceRow                                           ; price                       ; PriceRow:price                                     ;                                                           ; true                   ;
                                                ; PunchoutProduct:Currency                                           ; isocode                     ; Currency:isocode                                   ;                                                           ; true                   ;
                                                ; PunchoutProduct:Catalog                                            ; id                          ; Catalog:id                                         ;                                                           ; true                   ;
                                                ; PunchoutProduct:CatalogVersion                                     ; catalog                     ; CatalogVersion:catalog                             ; PunchoutProduct:Catalog                                   ; true                   ;
                                                ; PunchoutProduct:CatalogVersion                                     ; version                     ; CatalogVersion:version                             ;                                                           ; true                   ;
    
    INSERT_UPDATE IntegrationObjectItemVirtualAttribute; integrationObjectItem(integrationObject(code), code)[unique = true]; attributeName[unique = true]; retrievalDescriptor(code)
                                                       ; PunchoutProduct:Product                                            ; virtualProductCode                 ; virtualProductCode
    
    INSERT_UPDATE IntegrationObjectVirtualAttributeDescriptor; code[unique = true]; logicLocation       ; type(code)
                                                             ; virtualProductCode        ; model://virtualProductCode ; java.lang.String

2. Configure Consumed Destination

For data outbound, a consumed destination should be created to define the URL to which the data is push. You can create the consumed destination using ImpEx.
Sample ImpEx:

INSERT_UPDATE BasicCredential; id[unique = true]       ; username            ; password
                             ; PunchoutBasicCredential ; <destinationUsernameValue>; <destinationPasswordValue>

INSERT_UPDATE DestinationTarget; id[unique = true]
                               ; PunchoutDestinationTarget

INSERT_UPDATE ConsumedDestination; id[unique = true]           ; url                                                       ; destinationTarget(id)     ; credential(id)          ; active;
                                 ; PunchoutConsumedDestination ; <ConsumedDestinationUrl> ; PunchoutDestinationTarget ; PunchoutBasicCredential ; true

Note: The <destinationUsernameValue> and <destinationPasswordValue> for BasicCredential should be replaced by the credentials setup in the external system. The <ConsumedDestinationUrl> for ConsumedDestination should be replaced by the actual URL of the external system.

 3. Create Outbound Sync configuration

The outbound sync should be configured to publish new and updated Integration Object Items. You can create the outbound sync configuration using ImpEx.
Sample ImpEx:

INSERT_UPDATE OutboundChannelConfiguration; code[unique = true]           ; integrationObject(code); destination(id)             ; synchronizeDelete
                                          ; punchoutOutboundChannelConfig ; PunchoutProduct        ; PunchoutConsumedDestination ; true

INSERT_UPDATE OutboundSyncStreamConfigurationContainer; id[unique = true]
                                                      ; PunchoutOutboundChannelContainer

INSERT_UPDATE OutboundSyncStreamConfiguration; streamId[unique = true]                ; container(id)                    ; itemTypeForStream(code); outboundChannelConfiguration(code); whereClause
                                             ; punchoutOutboundChannel_Product_Stream ; PunchoutOutboundChannelContainer ; Product                ; punchoutOutboundChannelConfig     ; {item.catalogVersion} IN ({{SELECT {c.pk} FROM {CatalogVersion as c} WHERE {c.version}='Online' AND {c.catalog} IN ({{SELECT {cat.pk} FROM {Catalog as cat} WHERE {cat.id}='powertoolsProductCatalog'}})}})

INSERT_UPDATE OutboundSyncJob; code[unique = true]        ; streamConfigurationContainer(id)
                             ; punchoutOutboundChannelJob ; PunchoutOutboundChannelContainer

INSERT_UPDATE OutboundSyncCronJob; code[unique = true]            ; job(code)                  ; sessionLanguage(isoCode)
                                 ; punchoutOutboundChannelCronJob ; punchoutOutboundChannelJob ; en

# CronJob Triggers set to run every day at midnight
INSERT_UPDATE Trigger; active; second; minute; hour; day; month; year; cronExpression; cronJob(code)[unique = true]   ; relative
                     ; false ; 0     ; 0     ; 0   ; 0  ; 0    ; 0   ; 0 0 0 * * ?   ; punchoutOutboundChannelCronJob ; true

Note: The value of whereClause for OutboundSyncStreamConfiguration needs to be updated according to your own needs. You can filter products by attributes using whereClause. For example, the sample whereClause filters out Products that do not have Online as the CatalogVersion, or do not have powertoolsProductCatalog as the Catalog id. Make sure the value of active for Trigger is set to true if you want the CronJob to be triggered in the scheduled time.

Setup in SAP Cloud integration

In sample iFlow, We provides endpoint to receive the  data from Commerce and saved to tenant db;

 

We have another endpoints to trigger the convert and upload to procurement system, of coz, it also could be triggered by timer;

Of coz, there are lots of configurations need be take care standard timer/endpoint url, also includes procurement credential, API, catalog name.   Below is a sample of it

 

items Sample Category Comments
Destination path /messages_from_ec* To setup the destination where we receive EC messages

The URL should be unique in this tenant, finally we can get a URL as https://<SCI tenamt URL>/http/<destination path>.

Ensure a “*” is added, or we can’t receive deletion notification

Ariba network API https://service.ariba.com/ANCatalogProcessor.aw/ad/catalog To se which Ariba service we’ll call the URL we post to Ariba
Supplier network Id From an01665632054-t To compose upload header id of supplier
Supplier network Id Sender an01665632054-t Usually same as supplier id
Supplier credential myCredential1% The credential set in Ariba
Category name my-test-catelog The catalog name in Ariba
UserAgent Supplier The agent we show in upload header
Fields columns

FIELDNAMES: Supplier ID,Supplier Part ID,Manufacturer Part ID,Item Description,SPSC Code,Unit Price,Unit of Measure,Lead Time,Manufacturer Name,

Supplier URL,Manufacturer URL,Market Price,Supplier Part Auxiliary ID,Language,Currency,PunchOut Enabled,PunchOutLevel,Short Name,Image ,Thumbnail, deliveryregion, deliveryregion(Delivery Region), buyerpartid1(Buyer Part ID), buyerpartid1 , Delete

To compose catalog body The fields list
Fields Data AN01665632054-T,08335761,,new 6 in. (150 mm) Bench Grinder,27110000,95,EA,1,,,,,,en_US,USD,TRUE,product,,https://punchout.ellipticmarketing.com/media/18/IOjdeq5GkJ82usFQDh3XWFcbea4m9TclDcXZLjdm.jpeg, ,cn, cn, 132467, 132467 The fields sample which can pass buyer validation(different buyer may have different rules)
Fields mapping “code”: “Supplier Part ID”; “manufacturerAID”: “Manufacturer Part ID”; “manufacturerName” : “Manufacturer Name”;”unspcs”:”UNSPSC Provide the list to convert from Integration object to Ariba catalog
Currence USD
Timer trigger there is an UI to configure it Only needed if you try to solution 2. The time interval of it
Number of pulled messages 10000 When timer timeout in iFlow C, the max messages we read from db and compose to one update

 

Sample iFlow components as below

 

Test on real environment

Operations in SAP Commerce Cloud back office

After deployed SCI and set up properties in SAP cloud back office, try to trigger the upload

And try to check status in back office to see whether upload to SCI succeed.

 

Check status in SCI monitor

You also can check the status in SCI monitor and download the content if needed

Testing upload to procurement system

For testing, we just try to call another endpoint to emulate the timer event to upload catalog to Ariba.

Tried with wrong credential, you can see there is a 401 failure

 

After adjust the credential and redeploy the SCI and try it again, we can get 201 response from Ariba

 

Check content details in SCI

We can also download the attachment to see the contents we sends to Ariba and the response as well

Check result in Ariba supplier admin UI

Finally, we need ensure the catalog is uploaded in Ariba and validated, let’s login Ariba as supplier admin and check the catalog with summary and details

 

Now, we have uploaded product catalog from SAP Commerce Cloud to procurement system(Ariba). The next step is the vendor need to publish to buyer admin to check and approve, It’s out of the scope here.

 

Misc

  • In the sample iFlow, we only provides a feature which can merge and convert the exported product catalog to Ariba, Which means we support initial sync and upload sync. For product deletion(logic delete to disable the visibility and physical deletion) is not considered;
  • Testing only tested catalog with less than 10000 product; for big amount, user can try to adjust “Number of pulled messages” to a bigger number to avoid upload catalog to Ariba multi-times
  • In sample iFlow, we use incremental mode, if you want to use “Full” mode, you need change the scripts in iFlow;

 

Resources

Docs

Samples

You can download the iFlow/Impex file and step by step doc in SAP Note 3253587 as referral

 

More solutions

That’s just one solution in SAP Commerce to exporting product catalog, of coz you can also:

  • Replace SCI iFlow with your services
  • Call Commerce OOTB API to fetch products informations;
  • Create new cronJobs and run periodly inside the Commerce to export catalog to other system;
  • Use ERP to sync the catalog between Commerce and procurement system;
  • Others…

 

Your ideas and Feedbacks are welcome

Hope this is helpful for you to speed up your connection between SAP Commerce Cloud and procurement System. Stay tuned for more solutions. 🙂

If you have any feedback or suggestions, please feel free to add a comment below. I’ll try to check it time by time and reply them if I could.

Assigned Tags

      Be the first to leave a comment
      You must be Logged on to comment or reply to a post.