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:
- Do some small configurations in Integrations and Data Management side to export product info with some virtual properties
- Use SAP Cloud Integration to create endpoints to receive the exported info and converted to target procurement system’s format;
Below is a rough overall view of what’s we have done
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.
- In a web browser, navigate to the SAP Commerce Cloud Administration Console at https://localhost:9002/ and log in.
- Click Console > ImpEx Import
- 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
-
cXML Reference Guide – Ariba Network
-
SAP Ariba Catalog | Procurement content solutions
-
SAP Ariba APIs
-
Send cXML Message to Ariba Network as MIME Multipart
-
MIME Multipart Encoder for handling more than one attachments
-
Sending cXML with attachments to Ariba Network using Multipart Encoder in SAP integration suite/ CPI
-
Integrations and Data Management
-
SAP Cloud Integration
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.