Work with the punchout server-side extension

Commerce punchout functionality is provided through SSEs that can run on the Node.js server associated with your Commerce environment.

To use the punchout features, you must download the extensions from the Commerce administration server. You then customize the extension and upload it to your Node.js server. The punchout server-side extensions implement custom REST endpoints, which have the prefix /ccstorex/custom.

Commerce includes punchout server-side extensions that you can download and customize for your environment. This section describes the punchout extensions that are included with Commerce. See in Use developer tools to customize your store for details about how to download and customize server-side extensions.

The following table describes the punchout server-side extensions.

Server-side extension Description
punchout-app.zip Includes functionality that enables the punchout flow between the procurement system and Commerce. Use this sample application to customize the default functionality provided in the punchout-lib library.
punchout-lib.zip Supports setup, edit and complete flows for punchout in cXML standard with Commerce. Do not make any changes to this library.
purchase-order-app.zip Includes functionality that enables the purchase order flow between the procurement system and Commerce. Use this sample application to customize the default functionality provided in the purchase-order-lib library.
purchase-order-lib.zip Supports submitted orders in Commerce from procurement system’s purchase order in cXML format. Do not make any changes to this library.

Each ZIP file includes a readme.md file that describes classes and endpoints and includes information about how to install and extend the extension.

The server-side extensions provide the core punchout functionality with the following JavaScript classes. You can extend these classes, for example, to customize mappings or make additional Commerce REST API requests.

Class Name Description
PunchOutSetup Provides methods to authenticate, create the shopper token, and create the shopping cart in Commerce if re-punchout is required.
PunchOutComplete Provides methods that convert the order request body JSON to the cXML PunchOutOrderMessage, which is sent to the procurement system.
PurchaseOrder Provides methods that call the store priceOrder endpoint, check if prices are within tolerance limit, and create the order.
PunchOutUtils Provides utilities for functionality such as fetching SKU prices, calling Commerce APIs, and parsing XML.

Work with the punchout endpoints

This section describes the endpoints included in the punchout server-side extension. All the endpoints are public URLs and all requests must be sent via HTTPS.

punchoutSetUp and punchoutRedirection endpoints

Issue a POST request to the /ccstorex/custom/v1/punchOut/punchOutSetUp endpoint to establish a punchout (or re-punchout) session from the procurement system.

The request includes organization details, the shared secret key, and other relevant information. It generates the OAuth token for logging in the punchout shopper, caches the token, and generates a unique ID against it.

The GET /ccstorex/custom/v1/punchOut/punchOutRedirection/{sessionId} endpoint handles the redirection to the Commerce storefront page from the procurement system. Using the uniqueID from the URL, this endpoint fetches the actual OAuth token from the cache. A form, which has the OAuth token as the input, is automatically submitted to the storefront home page. On submission, the storefront extracts the OAuth token from the request body and logs the punchout shopper into the system. The cache entry is then deleted.

Note: For storefronts built with Open Storefront Framework, this configuration happens at the framework level at runtime.

The following example shows a sample cXML request body. In the header, Identity is the Organization ID and SharedSecret is the organization’s authorization code.

<cXML>
    <Header>
        <Sender>
            <Credential domain='organizationId'>
                <Identity>or-10001</Identity>
                <SharedSecret>authorization_code</SharedSecret>
            </Credential>
        </Sender>
    </Header>
    <Request>
        <PunchOutSetupRequest operation='create'>
            <BuyerCookie>1CX3L4843PPZO</BuyerCookie>
            <BrowserFormPost>
            <URL>http://localhost:1616/punchoutexit</URL>
          </BrowserFormPost>
            <Contact>
                <Name>buyer_name</Name>
                <Email>buyer_email</Email>
                <Extrinsic name='lastName'>punchout</Extrinsic>

            </Contact>
         </PunchOutSetupRequest>
    </Request>
</cXML>

The following example shows a sample cXML response, which returns the Commerce storefront URL returned by the punchoutRedirection endpoint, suffixed with the unique ID: as form-url-encoded values:

<cXML>
<PunchOutSetupResponse>
    <StartPage>
      <URL>http://admin-server-hostname/ccstorex/custom/v1/punchout/punchoutRedirection/d5a3990d-1d47-4b8d-9e27-5a4d269e3efe</URL>
    </StartPage>
</PunchOutSetupResponse>/
</cXML>

punchoutComplete endpoint

When the punchout shopper has finished adding items to their cart and wants to return to their procurement system, issue a POST request to the /ccstorex/custom/v1/punchOut/punchoutComplete endpoint to convert the order JSON to PunchOutOrderMessage cXML. See Add a punchout checkout button to the Order Summary widget for a sample widget that implements this endpoint.

The request body is a JSON representation of the punchout shopper’s order and the response body is a cXML representation of the order. See Order submit webhook for a sample JSON representation of an order.

purchaseOrder endpoint

Issue a POST request to the /ccstorex/custom/v1/punchOut/purchaseOrder endpoint to convert the procurement system’s purchase order cXML to JSON and create an order in Commerce.

By default, this server side extension supports invoice payment only, but. you can customize the extension to support other payment methods.

The following example shows a sample cXML request body.

<cXML>
  <Header>
      <Sender>
          <Credential domain='organizationId'>
              <Identity>or-100001</Identity>
              <SharedSecret>key</SharedSecret>
          </Credential>
      </Sender>
  </Header>
  <Request>
    <OrderRequest>
    <OrderRequestHeader orderID="DO102880" orderDate="2012-08-03T08:49:09+07:00" type="new">
      <Contact>
          <Name>First Name</Name>
          <Email>Email@example.com</Email>
          <Extrinsic name='lastName'>John_Smith</Extrinsic>
          <Extrinsic name='parentOrganization'>or-100001</Extrinsic>
      </Contact>
      <Total>
          <Money currency="USD">86.50</Money>
      </Total>
      <ShipTo>
          <Address isoCountryCode="US" addressID="1000467">
              <Name xml:lang="en">Acme, Inc.</Name>
              <PostalAddress name="default">
                  <DeliverTo>John Q. Smith</DeliverTo>
                  <DeliverTo>Buyers Headquarters</DeliverTo>
                   <Street>123 Main Street</Street>
                   <City>Mountain View</City>
                  <State>CA</State>
                  <PostalCode>94089</PostalCode>
                  <Country isoCountryCode='US'>United States</Country>
              </PostalAddress>
               <Email name="default">john_smith@example.com</Email>
              <Phone name="work">
                  <TelephoneNumber>
                      <CountryCode isoCountryCode="United States">1</CountryCode>
                                <AreaOrCityCode>800</AreaOrCityCode>
                                <Number>5555555</Number>
                            </TelephoneNumber>
                        </Phone>
          </Address>
      </ShipTo>
      <BillTo>
          <Address isoCountryCode="US" addressID="12">
              <Name xml:lang="en">Acme Accounts Payable</Name>
              <PostalAddress name="default">
                  <Street>124 Union Street</Street>
                  <City>San Francisco</City>
                  <State>CA</State>
                  <PostalCode>94128</PostalCode>
                  <Country isoCountryCode="US">United States</Country>
              </PostalAddress>
              <Phone name="work">
                  <TelephoneNumber>
                      <CountryCode isoCountryCode="US">1</CountryCode>
                      <AreaOrCityCode>415</AreaOrCityCode>
                      <Number>6666666</Number>
                  </TelephoneNumber>
              </Phone>
          </Address>
      </BillTo>
      <Shipping>
          <Money currency="USD">10.00</Money>
          <Description xml:lang="en-US">FedEx 2-day</Description>
      </Shipping>
      <Tax>
          <Money currency="USD">1.5</Money>
          <Description xml:lang="en">CA State Tax</Description>
      </Tax>
  </OrderRequestHeader>
  <ItemOut quantity="2" lineNumber="1">
      <ItemID>
          <SupplierPartID>Camera_1002</SupplierPartID>
          <SupplierPartAuxiliaryID>SKU_3005A</SupplierPartAuxiliaryID>
      </ItemID>
      <ItemDetail>
          <UnitPrice>
              <Money currency="USD">10</Money>
          </UnitPrice>
          <Description xml:lang="en">Laptop Notebook, 300 MHz</Description>
          <UnitOfMeasure>EA</UnitOfMeasure>
          <Classification domain="UNSPSC">43171801</Classification>
          <URL>http://www.example.com/Punchout.asp</URL>
          <Extrinsic name="ExtDescription">Enhanced keyboard</Extrinsic>
      </ItemDetail>
      <Shipping>
          <Money currency="USD">10.00</Money>
          <Description xml:lang="en-US">standardShippingMethod</Description>
      </Shipping>
      <ShipTo>
          <Address isoCountryCode="US" addressID="1000467">
              <Name xml:lang="en">Acme, Inc.</Name>
              <Email name="default">john_smith@exmaple.com</Email>
              <Phone name="work">
              <TelephoneNumber>
              <CountryCode isoCountryCode="United States">1</CountryCode>
              <AreaOrCityCode>800</AreaOrCityCode>
              <Number>5555555</Number>
              </TelephoneNumber>
              </Phone>
              <PostalAddress name="default">
                  <DeliverTo>John Q. Smith</DeliverTo>
                  <DeliverTo>Buyers Headquarters</DeliverTo>
                  <Street>123 Main Street</Street>
                  <City>Mountain View</City>
                  <State>CA</State>
                  <PostalCode>94089</PostalCode>
                  <Country isoCountryCode="US">United States</Country>
              </PostalAddress>
          </Address>
      </ShipTo>
      <Distribution>
          <Accounting name="DistributionCharge">
              <AccountingSegment id="7720">
                  <Name xml:lang="en-US">Account</Name>
                  <Description xml:lang="en-US">Office Supplies</Description>
              </AccountingSegment>
              <AccountingSegment id="610">
                  <Name xml:lang="en-US">Cost Center</Name>
                  <Description xml:lang="en-US">Engineering Mgt</Description>
              </AccountingSegment>
          </Accounting>
          <Charge>
              <Money currency="USD">20.00</Money>
              <!--<Percentage percent="20"/>
              <Money currency="USD">0.00</Money>-->
          </Charge>
      </Distribution>
      <Tolerances>
          <PriceTolerance>
              <Money currency="USD">100.00</Money>
          </PriceTolerance>
      </Tolerances>
   </ItemOut>
  </OrderRequest>
 </Request>
</cXML>

The following example shows a sample cXML response body for the previous request.

<cXML>
  <Response>
     <Status code="200" text="OK. Order ID: o30630"/>
  </Response>
</cXML>