Punchout Catalog feature integration

Edit on GitHub

Install Feature Core

Prerequisites

To start feature integration, overview, and install the necessary features:

NAME VERSION
Spryker Core 202009.0
Company Account 202009.0
Cart 202009.0
Product 202009.0
Vault 202009.0

1) Install the Required Modules Using Composer

Run the following command(s) to install the required modules:

composer require punchout-catalogs/punchout-catalog-spryker: "^2.0.0" --update-with-dependencies
Verification

Make sure that the following modules were installed:

MODULE EXPECTED DIRECTORY
PunchoutCatalogsSpryker vendor/punchout-catalogs/punchout-catalog-spryker

2) Set up Configuration

Attention

The following configuration creates a Zed access-point (for ERPs without authentication). Make sure that your Zed is only accessible through a secured channel and only for the trusted clients (ERPs).

Add the following configuration to your project:

CONFIGURATION SPECIFICATION NAMESPACE
Update config KernelConstants::PROJECT_NAMESPACES and KernelConstants::CORE_NAMESPACES Enables autoloading for Punchout module directories. None
Update config AclConstants::ACL_DEFAULT_RULES Allow access to PunchoutCatalog routes for ALL users. None
AuthConfig::getIgnorable() Allow access to PunchoutCatalog routes without authentication. Pyz\Zed\Auth
PunchoutCatalogConfig::getBaseUrlYves() Defines urls for Punchout API endpoints. Pyz\Zed\PunchoutCatalog

config/Shared/config_default.php

<?php
$config[KernelConstants::PROJECT_NAMESPACES] = [
    'PunchoutCatalog',
];

$config[KernelConstants::CORE_NAMESPACES] = [
    'PunchoutCatalog',
];

$config[AclConstants::ACL_DEFAULT_RULES] = [
[     
     [
        'bundle' => 'punchout-catalog',
        'controller' => 'request',
        'action' => 'index',
        'type' => 'allow',
    ],
];
Verification

Make sure that you can access http://zed.mysprykershop/punchout-catalog/request URL when logged in as any user, e.g. admin.
Make sure that you don’t receive class not found exception after “Setup Behaviour” section plugins registration.

src/Pyz/Zed/Auth/AuthConfig.php

<?php

namespace Pyz\Zed\Auth;

use Spryker\Zed\Auth\AuthConfig as SprykerAuthConfig;

class AuthConfig extends SprykerAuthConfig
{
    /**
     * @return array
     */
    public function getIgnorable()
    {
        $this->addIgnorable('punchout-catalog', 'request', 'index');

        return parent::getIgnorable();
    }
}
Verification

Make sure that you can access http://zed.mysprykershop/punchout-catalog/request without authentication.

config/Shared/config_default.php

<?php
/**
 * This file is part of the Spryker Suite.
 * For full license information, please view the LICENSE file that was distributed with this source code.
 */
namespace Pyz\Zed\PunchoutCatalog;
use PunchoutCatalog\Zed\PunchoutCatalog\PunchoutCatalogConfig as SprykerPunchoutCatalogConfig;

class PunchoutCatalogConfig extends SprykerPunchoutCatalogConfig
{
    /**
     * @return string[]
     */
    protected function getBaseUrlYves(): array
    {
        $domain = getenv('VM_PROJECT') ?: 'suite-nonsplit';

        return [
            'DE' => sprintf('http://www.de.%s.local', $domain),
            'AT' => sprintf('http://www.at.%s.local', $domain),
            'US' => sprintf('http://www.us.%s.local', $domain),
        ];
    }
}
Verification

Make sure that you do not receive an MissingYvesUrlConfigurationException exception when trying to click on the Transfer Cart button on a cart page (this button will be available when the “Feature Frontend” is fully installed).

3) Set up Database Schema and Transfer Objects

Run the following commands to apply database changes and generate entity and transfer changes:

console transfer:generate
console propel:install
console transfer:generate
Verification

Make sure that the following changes applied by checking your database:

DATABASE ENTITY TYPE EVENT
pgw_punchout_catalog_connection table created
pgw_punchout_catalog_connection_cart table created
pgw_punchout_catalog_connection_setup table created
pgw_punchout_catalog_transaction table created
Verification

Make sure that the following changes in transfer objects:

TRANSFER TYPE EVENT PATH
PunchoutCatalogSetupRequest class created src/Generated/Shared/Transfer/PunchoutCatalogSetupRequest
PunchoutCatalogSetupResponse class created src/Generated/Shared/Transfer/PunchoutCatalogSetupResponse
PunchoutCatalogProtocolData class created src/Generated/Shared/Transfer/PunchoutCatalogProtocolData
PunchoutCatalogProtocolDataCart class created src/Generated/Shared/Transfer/PunchoutCatalogProtocolDataCart
PunchoutCatalogProtocolDataOciCredentials class created src/Generated/Shared/Transfer/PunchoutCatalogProtocolDataOciCredentials
PunchoutCatalogProtocolDataCxmlCredentials class created src/Generated/Shared/Transfer/PunchoutCatalogProtocolDataCxmlCredentials
PunchoutCatalogConnectionCriteria class created src/Generated/Shared/Transfer/PunchoutCatalogConnectionCriteria
PunchoutCatalogConnectionCredentialSearch class created src/Generated/Shared/Transfer/PunchoutCatalogConnectionCredentialSearch
PunchoutCatalogConnectionList class created src/Generated/Shared/Transfer/PunchoutCatalogConnectionList
PunchoutCatalogCxmlCredential class created src/Generated/Shared/Transfer/PunchoutCatalogCxmlCredential
PunchoutCatalogOciCredential class created src/Generated/Shared/Transfer/PunchoutCatalogOciCredential
PunchoutCatalogConnection class created src/Generated/Shared/Transfer/PunchoutCatalogConnection
PunchoutCatalogConnectionCart class created src/Generated/Shared/Transfer/PunchoutCatalogConnectionCart
PunchoutCatalogConnectionSetup class created src/Generated/Shared/Transfer/PunchoutCatalogConnectionSetup
PunchoutCatalogCancelRequest class created src/Generated/Shared/Transfer/PunchoutCatalogCancelRequest
PunchoutCatalogCartResponse class created src/Generated/Shared/Transfer/PunchoutCatalogCartResponse
PunchoutCatalogCartResponseField class created src/Generated/Shared/Transfer/PunchoutCatalogCartResponseField
PunchoutCatalogDocumentCart class created src/Generated/Shared/Transfer/PunchoutCatalogDocumentCart
PunchoutCatalogDocumentCartItem class created src/Generated/Shared/Transfer/PunchoutCatalogDocumentCartItem
PunchoutCatalogDocumentCartCustomer class created src/Generated/Shared/Transfer/PunchoutCatalogDocumentCartCustomer
PunchoutCatalogDocumentCustomAttribute class created src/Generated/Shared/Transfer/PunchoutCatalogDocumentCustomAttribute
PunchoutCatalogMapping class created src/Generated/Shared/Transfer/PunchoutCatalogMapping
PunchoutCatalogMappingObject class created src/Generated/Shared/Transfer/PunchoutCatalogMappingObject
PunchoutCatalogMappingObjectField class created src/Generated/Shared/Transfer/PunchoutCatalogMappingObjectField
PunchoutCatalogMappingTransform class created src/Generated/Shared/Transfer/PunchoutCatalogMappingTransform
PunchoutCatalogMappingTransformParams class created src/Generated/Shared/Transfer/PunchoutCatalogMappingTransformParams
PunchoutCatalogCommonContext class created src/Generated/Shared/Transfer/PunchoutCatalogCommonContext
PunchoutCatalogCartRequestContext class created src/Generated/Shared/Transfer/PunchoutCatalogCartRequestContext
PunchoutCatalogCartResponseContext class created src/Generated/Shared/Transfer/PunchoutCatalogCartResponseContext
PunchoutCatalogDocumentCustomer class created src/Generated/Shared/Transfer/PunchoutCatalogDocumentCustomer
PunchoutCatalogDocumentCartItem class created src/Generated/Shared/Transfer/PunchoutCatalogDocumentCartItem
PunchoutCatalogSetupRequestDocument class created src/Generated/Shared/Transfer/PunchoutCatalogSetupRequestDocument
PunchoutCatalogEntryPoint class created src/Generated/Shared/Transfer/PunchoutCatalogEntryPoint
PunchoutCatalogEntryPointFilter class created src/Generated/Shared/Transfer/PunchoutCatalogEntryPointFilter

4) Add Translations

Append glossary according to your configuration:

data/import/glossary.csv
punchout-catalog.connection.list.title,Punch-out Catalog,en_US
punchout-catalog.connection.list.title,Ausstanzungskatalog,de_DE
punchout-catalog.connection.list.name,Name,en_US
punchout-catalog.connection.list.name,Name,de_DE
punchout-catalog.connection.list.date,Date,en_US
punchout-catalog.connection.list.date,Date,de_DE
punchout-catalog.connection.list.edit,Edit,en_US
punchout-catalog.connection.list.edit,Ändern,de_DE
punchout-catalog.connection.list.delete,Delete,en_US
punchout-catalog.connection.list.delete,Löschen,de_DE
punchout-catalog.connection.add-new-connection,New connection,en_US
punchout-catalog.connection.add-new-connection,Neu Anschluss,de_DE
punchout-catalog.connection.list.empty,No connections were found,en_US
punchout-catalog.connection.list.empty,Kein Anschluss wurde gefunden,de_DE
punchout-catalog.connection.create.title,Add new connection,en_US
punchout-catalog.connection.create.title,Neue Anschluss hinzufügen,de_DE
punchout-catalog.connection.name,Name,en_US
punchout-catalog.connection.name,Name,de_DE
punchout-catalog.connection.added,Connection added,en_US
punchout-catalog.connection.added,Connection wurde hinzufügt,de_DE
punchout-catalog.connection.updated,Connection updated,en_US
punchout-catalog.connection.updated,Anschluss wurde erfolgreich aktualisiert,de_DE
punchout-catalog.connection.not_updated,Error during connection update,en_US
punchout-catalog.connection.not_updated,Error during connection update DE,de_DE
punchout-catalog.error.is-not-punchout,Current session is not PunchOut,de_DE
punchout-catalog.error.is-not-punchout,Current session is not PunchOut,en_US
punchout-catalog.error.is-not-allowed,Current cart is not valid to transfer,de_DE
punchout-catalog.error.is-not-allowed,Current cart is not valid to transfer,en_US
punchout-catalog.error.missing-connection,Could not define PunchOut Connection,de_DE
punchout-catalog.error.missing-connection,Could not define PunchOut Connection,en_US
punchout-catalog.error.missing-cart-format,Could not define PunchOut Format,de_DE
punchout-catalog.error.missing-cart-format,Could not define PunchOut Format,en_US
punchout-catalog.error.general,An error happened,de_DE
punchout-catalog.error.general,An error happened,en_US
punchout-catalog.error.authentication,Authentication Failed,de_DE
punchout-catalog.error.authentication,Authentication Failed,en_US
punchout-catalog.error.invalid-data,Invalid PunchOut Format,de_DE
punchout-catalog.error.invalid-data,Invalid PunchOut Format,en_US
punchout-catalog.error.unexpected,An unexpected error happened,de_DE
punchout-catalog.error.unexpected,An unexpected error happened,en_US
punchout-catalog.cart.return,Transferring Cart to eProcurement client...,de_DE
punchout-catalog.cart.return,Transferring Cart to eProcurement client...,en_US
punchout-catalog.cart.checkout,Transfer Cart,de_DE
punchout-catalog.cart.checkout,Transfer Cart,en_US
punchout-catalog.cart.cancel,Cancel Cart & Return,de_DE
punchout-catalog.cart.cancel,Cancel Cart & Return,en_US
punchout-catalog.cart.go-to-transfer,Transfer Cart to eProcurement client,de_DE
punchout-catalog.cart.go-to-transfer,Transfer Cart to eProcurement client,en_US
punchout-catalog.cart.go-to-cancel,Cancel & Return to eProcurement client,de_DE
punchout-catalog.cart.go-to-cancel,Cancel & Return to eProcurement client,en_US
punchout-catalog.error.missing-company-business-unit,Missed Company Business Unit,de_DE
punchout-catalog.error.missing-company-business-unit,Missed Company Business Unit,en_US
punchout-catalog.error.missing-company-user,Missed Company User,de_DE
punchout-catalog.error.missing-company-user,Missed Company User,en_US
punchout-catalog.error.invalid.document.data,Invalid Document Data,de_DE
punchout-catalog.error.invalid.document.data,Invalid Document Data,en_US
punchout-catalog.error.invalid.source.data,Invalid Source Data,de_DE
punchout-catalog.error.invalid.source.data,Invalid Source Data,en_US
punchout-catalog.error.invalid.mapping.source,Invalid Mapping Source,de_DE
punchout-catalog.error.invalid.mapping.source,Invalid Mapping Source,en_US
punchout-catalog.error.invalid.mapping.format,Invalid Mapping Format,de_DE
punchout-catalog.error.invalid.mapping.format,Invalid Mapping Format,en_US
punchout-catalog.error.too-many-company-users,Customer should have only one Company user to login,de_DE
punchout-catalog.error.too-many-company-users,Customer should have only one Company user to login,en_US

Run the following console command to import data:

console data:import glossary
Verification

Make sure that in the database the configured data are added to the spy_glossary table.

5) Import Data

Import Punchout Catalog Data

Prepare your data according to your requirements using our demo data:

vendor/punchout-catalogs/punchout-catalog-spryker/data/import/punchout_catalog_connection.csv
business_unit_key,username,password,credentials,is_active,type,format,name,mapping
business-unit-regular-1,user_1,user_1_pass,,1,setup_request,cxml,Client 1 - cXml - User 1,"{
  ""customer"": {
    ""fields"": {
      ""first_name"": {
        ""path"": ""/cXML/Request[1]/PunchOutSetupRequest[1]/Extrinsic[@name='FirstName']""
      },
      ""last_name"": {
        ""path"": ""/cXML/Request[1]/PunchOutSetupRequest[1]/Extrinsic[@name='LastName']""
      },
      ""email"": {
        ""path"": ""/cXML/Request[1]/PunchOutSetupRequest[1]/Extrinsic[@name='UserEmail']""
      }
    }
  },
  ""cart_item"": {
    ""fields"": {
      ""internal_id"":{
        ""path"": ""/cXML/Request[1]/PunchOutSetupRequest[1]/ItemOut/ItemID[1]/SupplierPartAuxiliaryID""
      }
    }
  }
}"
business-unit-regular-1,user_1,user_1_pass,,1,setup_request,oci,Client 1 - Oci - User 1,"{
  ""customer"": {
    ""fields"": {
      ""first_name"": {
        ""path"": ""first_name""
      },
      ""last_name"": {
        ""path"": ""last_name""
      },
      ""email"": {
        ""path"": ""email""
      }
    }
  }
}"
Supplier_Department,user_2,user_2_pass,,1,setup_request,cxml,Client 1 - cXml - User 2,"{
  ""customer"": {
    ""fields"": {
      ""first_name"": {
        ""path"": ""/cXML/Request[1]/PunchOutSetupRequest[1]/Contact[1]/Name[1]"",
        ""transform"": [{
          ""split"": {
            ""sep"": ""\\s"",
            ""index"": ""1""
          }
        }]
      },
      ""last_name"": {
        ""path"": ""/cXML/Request[1]/PunchOutSetupRequest[1]/Contact[1]/Name[1]"",
        ""transform"": [{
          ""split"": {
            ""sep"": ""\\s"",
            ""index"": ""2""
          }
        }]
      },
      ""email"": {
        ""path"": ""/cXML/Request[1]/PunchOutSetupRequest[1]/Contact[1]/Email[1]""
      }
    }
  },
  ""cart_item"": {
    ""fields"": {
      ""internal_id"":{
        ""path"": ""/cXML/Request[1]/PunchOutSetupRequest[1]/ItemOut/ItemID[1]/SupplierPartAuxiliaryID""
      }
    }
  }
}"
Supplier_Department,user_2,user_2_pass,,1,setup_request,oci,Client 2 - Oci - User 2,"{
  ""customer"": {
    ""fields"": {
      ""first_name"": {
        ""path"": ""first_name""
      },
      ""last_name"": {
        ""path"": ""last_name""
      },
      ""email"": {
        ""path"": ""email""
      }
    }
  }
}"
business-unit-regular-1,user_10,user_10_pass,,1,setup_request,cxml,Client 2 - cXml - User 1,"{}"
business-unit-regular-1,user_20,user_20_pass,,0,setup_request,cxml,Client 2 - cXml - User 20,"{}"
business-unit-mitte-1,user_30,user_30_pass,,1,setup_request,cxml,Client 3 - cXml - User 3,"{
  ""customer"": {
    ""fields"": {
      ""first_name"": {
        ""path"": ""/cXML/Request[1]/PunchOutSetupRequest[1]/Extrinsic[@name='FirstName']""
      },
      ""last_name"": {
        ""path"": ""/cXML/Request[1]/PunchOutSetupRequest[1]/Extrinsic[@name='LastName']""
      },
      ""email"": {
        ""path"": ""/cXML/Request[1]/PunchOutSetupRequest[1]/Extrinsic[@name='UserEmail']""
      }
    }
  }
}"
business-unit-mitte-1,user_30,user_30_pass,,1,setup_request,oci,Client 3 - Oci - User 3,"{
  ""customer"": {
    ""fields"": {
      ""first_name"": {
        ""path"": ""first_name""
      },
      ""last_name"": {
        ""path"": ""last_name""
      },
      ""email"": {
        ""path"": ""email""
      }
    }
  }
}"
COLUMN REQUIRED DATA TYPE DATA EXAMPLE
business_unit_key mandatory string Sales_Department
username mandatory string user_1
password mandatory string user_1_pass
credentials no string
is_active mandatory bool `1
type mandatory string setup_request
format mandatory string `cxml
name mandatory string Client 1 - cXml - User 2
mapping mandatory string

Data Example for mapping:

{
  "customer": {
    "fields": {
      "first_name": {
        "path": "/cXML/Request[1]/PunchOutSetupRequest[1]/Extrinsic[@name='FirstName']"
      },
      "last_name": {
        "path": "/cXML/Request[1]/PunchOutSetupRequest[1]/Extrinsic[@name='LastName']"
      },
      "email": {
        "path": "/cXML/Request[1]/PunchOutSetupRequest[1]/Extrinsic[@name='UserEmail']"
      }
    }
  },
  "cart_item": {
    "fields": {
      "internal_id":{
        "path": "/cXML/Request[1]/PunchOutSetupRequest[1]/ItemOut/ItemID[1]/SupplierPartAuxiliaryID"
      }
    }
  }
}
vendor/punchout-catalogs/punchout-catalog-spryker/data/import/punchout_catalog_connection_cart.csv
connection_name,default_supplier_id,max_description_length,bundle_mode,totals_mode,encoding,mapping
Client 1 - cXml - User 1,spryker_sup_1,100,composite,header,base64,"{
  ""cart"": {
    ""fields"": {
      ""grand_total"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Total[1]/Money[1]""
      },

      ""tax_total"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Tax[1]/Money[1]""
      },
      ""tax_description"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Tax[1]/Description[1]""
      },

      ""discount_total"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Discount[1]/Money[1]""
      },
      ""discount_description"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Discount[1]/Description[1]""
      },

      ""currency"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Total[1]/Money[1]/@currency,/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Tax[1]/Money[1]/@currency,/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Discount[1]/Money[1]/@currency"",
                                ""append"": true
      },
                        ""cart_note"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Comments[1]""
      }
    }
  },
  ""cart_item"": {
    ""fields"": {
      ""line_number"": {
        ""path"": ""@lineNumber""
      },
                        ""parent_line_number"": {
        ""path"": ""@parentLineNumber""
      },
                        ""item_type"": {
        ""path"": ""@itemType""
      },
                        ""composite_item_type"": {
        ""path"": ""@compositeItemType""
      },
      ""quantity"": {
        ""path"": ""@quantity""
      },
      ""internal_id"": {
        ""path"": ""ItemID[1]/SupplierPartAuxiliaryID[1]""
      },
                        ""sku"": {
        ""path"": ""ItemID[1]/SupplierPartID[1],ItemDetail[1]/BuyerPartID[1],ItemDetail[1]/ManufacturerPartID[1]""
      },
                        ""unit_total"": {
        ""path"": ""ItemDetail[1]/UnitPrice[1]/Money[1]""
      },
      ""currency"": {
        ""path"": ""ItemDetail[1]/UnitPrice[1]/Money[1]/@currency""
      },
      ""name"": {
        ""path"": ""ItemDetail[1]/Description[1]/ShortName""
      },
      ""long_description"": {
        ""path"": ""ItemDetail[1]/Description[1]""
      },
      ""uom"": {
        ""path"": ""ItemDetail[1]/UnitOfMeasure[1]"",
        ""transform"": [{
          ""default"": {
            ""value"": ""EA""
          }
        }]
      },
      ""brand"": {
        ""path"": ""ItemDetail[1]/ManufacturerName[1]""
      },
      ""supplier_id"": {
        ""path"": ""ItemDetail[1]/SupplierID[1]""
      },
      ""cart_note"": {
        ""path"": ""ItemDetail[1]/Comments[1]""
      },
      ""image_url"": {
        ""path"": ""ItemDetail[1]/Extrinsic[@name='ImageURL']""
      },
      ""locale"": {
        ""path"": ""ItemDetail[1]/Description[1]/@xml:lang""
      }
    }
  }
}"
Client 1 - Oci - User 1,spryker_sup_2,128,composite,line,,"
{
  ""cart_item"": {
    ""fields"": {
      ""quantity"": {
        ""path"": ""NEW_ITEM-QUANTITY[%line_number%]""
      },
      ""internal_id"": {
        ""path"": ""NEW_ITEM-EXT_PRODUCT_ID[%line_number%]""
      },
      ""parent_line_number"": {
        ""path"": ""NEW_ITEM-PARENT_ID[%line_number%]""
      },
      ""item_type"": {
        ""path"": ""NEW_ITEM-ITEM_TYPE[%line_number%]"",
        ""transform"":
                                [
                                        {
                                                ""map"": {
                                                        ""value"": ""composite"",
                                                        ""result"": ""R""
                                                }
                                        },
                                        {
                                                ""map"": {
                                                        ""value"": ""item"",
                                                        ""result"": ""O""
                                                }
                                        }
        ]
      },
      ""sku"": {
        ""path"": ""NEW_ITEM-VENDORMAT[%line_number%],NEW_ITEM-MANUFACTMAT[%line_number%]""
      },
      ""currency"": {
        ""path"": ""NEW_ITEM-CURRENCY[%line_number%]""
      },
      ""unit_total"": {
        ""path"": ""NEW_ITEM-PRICE[%line_number%]""
      },
      ""name"": {
        ""path"": ""NEW_ITEM-DESCRIPTION[%line_number%]""
      },
      ""long_description"": {
        ""path"": ""NEW_ITEM-LONGTEXT_%line_number%:132[]""
      },
      ""uom"": {
        ""path"": ""NEW_ITEM-UNIT[%line_number%]"",
        ""transform"": [{
          ""default"": {
            ""value"": ""EA""
          }
        }]
      },
      ""unspsc"": {
        ""path"": ""NEW_ITEM-MATGROUP[%line_number%]""
      },
      ""supplier_id"": {
        ""path"": ""NEW_ITEM-VENDOR[%line_number%]""
      }
    }
  }
}"
Client 1 - cXml - User 2,spryker_sup_3,,single,line,url-encoded,"{
  ""cart"": {
    ""fields"": {
      ""grand_total"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Total[1]/Money[1]""
      },

      ""tax_total"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Tax[1]/Money[1]""
      },
      ""tax_description"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Tax[1]/Description[1]""
      },

      ""discount_total"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Discount[1]/Money[1]""
      },
      ""discount_description"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Discount[1]/Description[1]""
      },

      ""currency"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Total[1]/Money[1]/@currency,/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Tax[1]/Money[1]/@currency,/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Discount[1]/Money[1]/@currency"",
        ""append"": true
      },
                        ""cart_note"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Comments[1]""
      }
    }
  },
  ""cart_item"": {
    ""fields"": {
      ""line_number"": {
        ""path"": ""@lineNumber""
      },
                        ""parent_line_number"": {
        ""path"": ""@parentLineNumber""
      },
                        ""item_type"": {
        ""path"": ""@itemType""
      },
                        ""composite_item_type"": {
        ""path"": ""@compositeItemType""
      },
      ""quantity"": {
        ""path"": ""@quantity""
      },
      ""internal_id"": {
        ""path"": ""ItemID[1]/SupplierPartAuxiliaryID[1]""
      },
      ""sku"": {
        ""path"": ""ItemID[1]/SupplierPartID[1],ItemDetail[1]/BuyerPartID[1],ItemDetail[1]/ManufacturerPartID[1]""
      },
      ""unit_total"": {
        ""path"": ""ItemDetail[1]/UnitPrice[1]/Money[1]""
      },
      ""currency"": {
        ""path"": ""ItemDetail[1]/UnitPrice[1]/Money[1]/@currency""
      },
      ""name"": {
        ""path"": ""ItemDetail[1]/Description[1]/ShortName""
      },
      ""long_description"": {
        ""path"": ""ItemDetail[1]/Description[1]""
      },
      ""uom"": {
        ""path"": ""ItemDetail[1]/UnitOfMeasure[1]"",
        ""transform"": [{
          ""default"": {
            ""value"": ""EA""
          }
        }]
      },
      ""brand"": {
        ""path"": ""ItemDetail[1]/ManufacturerName[1]""
      },
      ""supplier_id"": {
        ""path"": ""ItemDetail[1]/SupplierID[1]""
      },
      ""cart_note"": {
        ""path"": ""ItemDetail[1]/Comments[1]""
      },
      ""image_url"": {
        ""path"": ""ItemDetail[1]/Extrinsic[@name='ImageURL']""
      },
      ""locale"": {
        ""path"": ""ItemDetail[1]/Description[1]/@xml:lang""
      },
      ""options"": {
        ""path"": ""ItemDetail[1]/Extrinsic/customOption()"",
        ""multiple"": true
      }
    }
  },
  ""customOption"": {
    ""fields"": {
      ""code"": {
        ""path"": ""@name""
      },
      ""value"": {
        ""path"": ""./""
      }
    }
  }
}"
Client 2 - Oci - User 2,spryker_sup_6,,single,line,,"
{
  ""cart_item"": {
    ""fields"": {
      ""quantity"": {
        ""path"": ""NEW_ITEM-QUANTITY[%line_number%]""
      },
      ""internal_id"": {
        ""path"": ""NEW_ITEM-EXT_PRODUCT_ID[%line_number%]""
      },
      ""parent_line_number"": {
        ""path"": ""NEW_ITEM-PARENT_ID[%line_number%]""
      },
      ""item_type"": {
        ""path"": ""NEW_ITEM-ITEM_TYPE[%line_number%]"",
        ""transform"":
                                [
                                        {
                                                ""map"": {
                                                        ""value"": ""composite"",
                                                        ""result"": ""R""
                                                }
                                        },
                                        {
                                                ""map"": {
                                                        ""value"": ""item"",
                                                        ""result"": ""O""
                                                }
                                        }
        ]
      },
      ""sku"": {
        ""path"": ""NEW_ITEM-VENDORMAT[%line_number%],NEW_ITEM-MANUFACTMAT[%line_number%]""
      },
      ""currency"": {
        ""path"": ""NEW_ITEM-CURRENCY[%line_number%]""
      },
      ""unit_total"": {
        ""path"": ""NEW_ITEM-PRICE[%line_number%]""
      },
      ""name"": {
        ""path"": ""NEW_ITEM-DESCRIPTION[%line_number%]""
      },
      ""long_description"": {
        ""path"": ""NEW_ITEM-LONGTEXT_%line_number%:132[]""
      },
      ""uom"": {
        ""path"": ""NEW_ITEM-UNIT[%line_number%]"",
        ""transform"": [{
          ""default"": {
            ""value"": ""EA""
          }
        }]
      },
      ""unspsc"": {
        ""path"": ""NEW_ITEM-MATGROUP[%line_number%]""
      },
      ""supplier_id"": {
        ""path"": ""NEW_ITEM-VENDOR[%line_number%]""
      }
    }
  }
}"
Client 2 - cXml - User 1,spryker_sup_4,,composite,header,url-encoded,{}
Client 3 - cXml - User 3,spryker_sup_5,,composite,line,base64,{}
Client 2 - cXml - User 20,spryker_sup_5,,composite,line,base64,{}
Client 3 - Oci - User 3,spryker_sup_5,,composite,line,,{}
COLUMN REQUIRED DATA TYPE DATA EXAMPLE
connection_name mandatory string Client 1 - cXml - User 1
default_supplier_id mandatory string 323332
max_description_length mandatory integer 9999
bundle_mode mandatory string `composite
totals_mode mandatory string `list
encoding mandatory string base64
mapping mandatory string

Data Example for mapping:

{
  "cart": {
    "fields": {
      "grand_total": {
        "path": "/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Total[1]/Money[1]"
      },

      "tax_total": {
        "path": "/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Tax[1]/Money[1]"
      },
      "tax_description": {
        "path": "/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Tax[1]/Description[1]"
      },

      "discount_total": {
        "path": "/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Discount[1]/Money[1]"
      },
      "discount_description": {
        "path": "/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Discount[1]/Description[1]"
      },

      "currency": {
        "path": "/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Total[1]/Money[1]/@currency,/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Tax[1]/Money[1]/@currency,/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Discount[1]/Money[1]/@currency",
        "append": true
      },
                  "cart_note": {
        "path": "/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Comments[1]"
      }
    }
  },
  "cart_item": {
    "fields": {
      "line_number": {
        "path": "@lineNumber"
      },
                  "parent_line_number": {
        "path": "@parentLineNumber"
      },
                  "item_type": {
        "path": "@itemType"
      },
                  "composite_item_type": {
        "path": "@compositeItemType"
      },
      "quantity": {
        "path": "@quantity"
      },
      "internal_id": {
        "path": "ItemID[1]/SupplierPartAuxiliaryID[1]"
      },
      "sku": {
        "path": "ItemID[1]/SupplierPartID[1],ItemDetail[1]/BuyerPartID[1],ItemDetail[1]/ManufacturerPartID[1]"
      },
      "unit_total": {
        "path": "ItemDetail[1]/UnitPrice[1]/Money[1]"
      },
      "currency": {
        "path": "ItemDetail[1]/UnitPrice[1]/Money[1]/@currency"
      },
      "name": {
        "path": "ItemDetail[1]/Description[1]/ShortName"
      },
      "long_description": {
        "path": "ItemDetail[1]/Description[1]"
      },
      "uom": {
        "path": "ItemDetail[1]/UnitOfMeasure[1]",
        "transform": [{
          "default": {
            "value": "EA"
          }
        }]
      },
      "brand": {
        "path": "ItemDetail[1]/ManufacturerName[1]"
      },
      "supplier_id": {
        "path": "ItemDetail[1]/SupplierID[1]"
      },
      "cart_note": {
        "path": "ItemDetail[1]/Comments[1]"
      },
      "image_url": {
        "path": "ItemDetail[1]/Extrinsic[@name='ImageURL']"
      },
      "locale": {
        "path": "ItemDetail[1]/Description[1]/@xml:lang"
      },
      "options": {
        "path": "ItemDetail[1]/Extrinsic/customOption()",
        "multiple": true
      }
    }
  },
  "customOption": {
    "fields": {
      "code": {
        "path": "@name"
      },
      "value": {
        "path": "./"
      }
    }
  }
}
vendor/punchout-catalogs/punchout-catalog-spryker/data/import/punchout_catalog_connection_setup.csv
connection_name,default_supplier_id,max_description_length,bundle_mode,totals_mode,encoding,mapping
Client 1 - cXml - User 1,spryker_sup_1,100,composite,header,base64,"{
  ""cart"": {
    ""fields"": {
      ""grand_total"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Total[1]/Money[1]""
      },

      ""tax_total"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Tax[1]/Money[1]""
      },
      ""tax_description"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Tax[1]/Description[1]""
      },

      ""discount_total"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Discount[1]/Money[1]""
      },
      ""discount_description"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Discount[1]/Description[1]""
      },

      ""currency"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Total[1]/Money[1]/@currency,/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Tax[1]/Money[1]/@currency,/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Discount[1]/Money[1]/@currency"",
                                ""append"": true
      },
                        ""cart_note"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Comments[1]""
      }
    }
  },
  ""cart_item"": {
    ""fields"": {
      ""line_number"": {
        ""path"": ""@lineNumber""
      },
                        ""parent_line_number"": {
        ""path"": ""@parentLineNumber""
      },
                        ""item_type"": {
        ""path"": ""@itemType""
      },
                        ""composite_item_type"": {
        ""path"": ""@compositeItemType""
      },
      ""quantity"": {
        ""path"": ""@quantity""
      },
      ""internal_id"": {
        ""path"": ""ItemID[1]/SupplierPartAuxiliaryID[1]""
      },
                        ""sku"": {
        ""path"": ""ItemID[1]/SupplierPartID[1],ItemDetail[1]/BuyerPartID[1],ItemDetail[1]/ManufacturerPartID[1]""
      },
                        ""unit_total"": {
        ""path"": ""ItemDetail[1]/UnitPrice[1]/Money[1]""
      },
      ""currency"": {
        ""path"": ""ItemDetail[1]/UnitPrice[1]/Money[1]/@currency""
      },
      ""name"": {
        ""path"": ""ItemDetail[1]/Description[1]/ShortName""
      },
      ""long_description"": {
        ""path"": ""ItemDetail[1]/Description[1]""
      },
      ""uom"": {
        ""path"": ""ItemDetail[1]/UnitOfMeasure[1]"",
        ""transform"": [{
          ""default"": {
            ""value"": ""EA""
          }
        }]
      },
      ""brand"": {
        ""path"": ""ItemDetail[1]/ManufacturerName[1]""
      },
      ""supplier_id"": {
        ""path"": ""ItemDetail[1]/SupplierID[1]""
      },
      ""cart_note"": {
        ""path"": ""ItemDetail[1]/Comments[1]""
      },
      ""image_url"": {
        ""path"": ""ItemDetail[1]/Extrinsic[@name='ImageURL']""
      },
      ""locale"": {
        ""path"": ""ItemDetail[1]/Description[1]/@xml:lang""
      }
    }
  }
}"
Client 1 - Oci - User 1,spryker_sup_2,128,composite,line,,"
{
  ""cart_item"": {
    ""fields"": {
      ""quantity"": {
        ""path"": ""NEW_ITEM-QUANTITY[%line_number%]""
      },
      ""internal_id"": {
        ""path"": ""NEW_ITEM-EXT_PRODUCT_ID[%line_number%]""
      },
      ""parent_line_number"": {
        ""path"": ""NEW_ITEM-PARENT_ID[%line_number%]""
      },
      ""item_type"": {
        ""path"": ""NEW_ITEM-ITEM_TYPE[%line_number%]"",
        ""transform"":
                                [
                                        {
                                                ""map"": {
                                                        ""value"": ""composite"",
                                                        ""result"": ""R""
                                                }
                                        },
                                        {
                                                ""map"": {
                                                        ""value"": ""item"",
                                                        ""result"": ""O""
                                                }
                                        }
        ]
      },
      ""sku"": {
        ""path"": ""NEW_ITEM-VENDORMAT[%line_number%],NEW_ITEM-MANUFACTMAT[%line_number%]""
      },
      ""currency"": {
        ""path"": ""NEW_ITEM-CURRENCY[%line_number%]""
      },
      ""unit_total"": {
        ""path"": ""NEW_ITEM-PRICE[%line_number%]""
      },
      ""name"": {
        ""path"": ""NEW_ITEM-DESCRIPTION[%line_number%]""
      },
      ""long_description"": {
        ""path"": ""NEW_ITEM-LONGTEXT_%line_number%:132[]""
      },
      ""uom"": {
        ""path"": ""NEW_ITEM-UNIT[%line_number%]"",
        ""transform"": [{
          ""default"": {
            ""value"": ""EA""
          }
        }]
      },
      ""unspsc"": {
        ""path"": ""NEW_ITEM-MATGROUP[%line_number%]""
      },
      ""supplier_id"": {
        ""path"": ""NEW_ITEM-VENDOR[%line_number%]""
      }
    }
  }
}"
Client 1 - cXml - User 2,spryker_sup_3,,single,line,url-encoded,"{
  ""cart"": {
    ""fields"": {
      ""grand_total"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Total[1]/Money[1]""
      },

      ""tax_total"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Tax[1]/Money[1]""
      },
      ""tax_description"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Tax[1]/Description[1]""
      },

      ""discount_total"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Discount[1]/Money[1]""
      },
      ""discount_description"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Discount[1]/Description[1]""
      },

      ""currency"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Total[1]/Money[1]/@currency,/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Tax[1]/Money[1]/@currency,/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Discount[1]/Money[1]/@currency"",
        ""append"": true
      },
                        ""cart_note"": {
        ""path"": ""/cXML/Message[1]/PunchOutOrderMessage[1]/PunchOutOrderMessageHeader[1]/Comments[1]""
      }
    }
  },
  ""cart_item"": {
    ""fields"": {
      ""line_number"": {
        ""path"": ""@lineNumber""
      },
                        ""parent_line_number"": {
        ""path"": ""@parentLineNumber""
      },
                        ""item_type"": {
        ""path"": ""@itemType""
      },
                        ""composite_item_type"": {
        ""path"": ""@compositeItemType""
      },
      ""quantity"": {
        ""path"": ""@quantity""
      },
      ""internal_id"": {
        ""path"": ""ItemID[1]/SupplierPartAuxiliaryID[1]""
      },
      ""sku"": {
        ""path"": ""ItemID[1]/SupplierPartID[1],ItemDetail[1]/BuyerPartID[1],ItemDetail[1]/ManufacturerPartID[1]""
      },
      ""unit_total"": {
        ""path"": ""ItemDetail[1]/UnitPrice[1]/Money[1]""
      },
      ""currency"": {
        ""path"": ""ItemDetail[1]/UnitPrice[1]/Money[1]/@currency""
      },
      ""name"": {
        ""path"": ""ItemDetail[1]/Description[1]/ShortName""
      },
      ""long_description"": {
        ""path"": ""ItemDetail[1]/Description[1]""
      },
      ""uom"": {
        ""path"": ""ItemDetail[1]/UnitOfMeasure[1]"",
        ""transform"": [{
          ""default"": {
            ""value"": ""EA""
          }
        }]
      },
      ""brand"": {
        ""path"": ""ItemDetail[1]/ManufacturerName[1]""
      },
      ""supplier_id"": {
        ""path"": ""ItemDetail[1]/SupplierID[1]""
      },
      ""cart_note"": {
        ""path"": ""ItemDetail[1]/Comments[1]""
      },
      ""image_url"": {
        ""path"": ""ItemDetail[1]/Extrinsic[@name='ImageURL']""
      },
      ""locale"": {
        ""path"": ""ItemDetail[1]/Description[1]/@xml:lang""
      },
      ""options"": {
        ""path"": ""ItemDetail[1]/Extrinsic/customOption()"",
        ""multiple"": true
      }
    }
  },
  ""customOption"": {
    ""fields"": {
      ""code"": {
        ""path"": ""@name""
      },
      ""value"": {
        ""path"": ""./""
      }
    }
  }
}"
Client 2 - Oci - User 2,spryker_sup_6,,single,line,,"
{
  ""cart_item"": {
    ""fields"": {
      ""quantity"": {
        ""path"": ""NEW_ITEM-QUANTITY[%line_number%]""
      },
      ""internal_id"": {
        ""path"": ""NEW_ITEM-EXT_PRODUCT_ID[%line_number%]""
      },
      ""parent_line_number"": {
        ""path"": ""NEW_ITEM-PARENT_ID[%line_number%]""
      },
      ""item_type"": {
        ""path"": ""NEW_ITEM-ITEM_TYPE[%line_number%]"",
        ""transform"":
                                [
                                        {
                                                ""map"": {
                                                        ""value"": ""composite"",
                                                        ""result"": ""R""
                                                }
                                        },
                                        {
                                                ""map"": {
                                                        ""value"": ""item"",
                                                        ""result"": ""O""
                                                }
                                        }
        ]
      },
      ""sku"": {
        ""path"": ""NEW_ITEM-VENDORMAT[%line_number%],NEW_ITEM-MANUFACTMAT[%line_number%]""
      },
      ""currency"": {
        ""path"": ""NEW_ITEM-CURRENCY[%line_number%]""
      },
      ""unit_total"": {
        ""path"": ""NEW_ITEM-PRICE[%line_number%]""
      },
      ""name"": {
        ""path"": ""NEW_ITEM-DESCRIPTION[%line_number%]""
      },
      ""long_description"": {
        ""path"": ""NEW_ITEM-LONGTEXT_%line_number%:132[]""
      },
      ""uom"": {
        ""path"": ""NEW_ITEM-UNIT[%line_number%]"",
        ""transform"": [{
          ""default"": {
            ""value"": ""EA""
          }
        }]
      },
      ""unspsc"": {
        ""path"": ""NEW_ITEM-MATGROUP[%line_number%]""
      },
      ""supplier_id"": {
        ""path"": ""NEW_ITEM-VENDOR[%line_number%]""
      }
    }
  }
}"
Client 2 - cXml - User 1,spryker_sup_4,,composite,header,url-encoded,{}
Client 3 - cXml - User 3,spryker_sup_5,,composite,line,base64,{}
Client 2 - cXml - User 20,spryker_sup_5,,composite,line,base64,{}
Client 3 - Oci - User 3,spryker_sup_5,,composite,line,,{}
COLUMN REQUIRED DATA TYPE DATA EXAMPLE DATA EXPLANATION
connection_name mandatory string Client 1 - cXml - User 1 Name of the PunchoutCatalog connection.
business_unit_key mandatory string Sales_Department Allows customers to configure in which BU the new company user should be created (dynamic login mode)
company_user_key mandatory string Ottom--1 Defines a dedicated company user that will be used by all ERP users (single company user login mode)
login_mode mandatory string `single_user dynamic_user_creation`

Register the following plugins to enable data import:

PLUGIN SPECIFICATION PREREQUISITES NAMESPACE
PunchoutCatalogConnectionDataImportPlugin Imports connections data into the database. None PunchoutCatalog\Zed\PunchoutCatalog\Communication\Plugin\DataImport
PunchoutCatalogSetupDataImportPlugin Imports connections setup data into the database. None PunchoutCatalog\Zed\PunchoutCatalog\Communication\Plugin\DataImport
PunchoutCatalogCartDataImportPlugin Imports connections cart data into the database. None PunchoutCatalog\Zed\PunchoutCatalog\Communication\Plugin\DataImport

src/Pyz/Zed/DataImport/DataImportDependencyProvider.php

<?php

namespace Pyz\Zed\DataImport;

use Spryker\Zed\DataImport\DataImportDependencyProvider as SprykerDataImportDependencyProvider;
use PunchoutCatalog\Zed\PunchoutCatalog\Communication\Plugin\DataImport\PunchoutCatalogCartDataImportPlugin;
use PunchoutCatalog\Zed\PunchoutCatalog\Communication\Plugin\DataImport\PunchoutCatalogConnectionDataImportPlugin;
use PunchoutCatalog\Zed\PunchoutCatalog\Communication\Plugin\DataImport\PunchoutCatalogSetupDataImportPlugin;

class DataImportDependencyProvider extends SprykerDataImportDependencyProvider
{
    protected function getDataImporterPlugins(): array
    {
        return [
            new PunchoutCatalogConnectionDataImportPlugin(),
            new PunchoutCatalogSetupDataImportPlugin(),
            new PunchoutCatalogCartDataImportPlugin(),     
        ];
    }
}

Run the following console command to import data:

console data:import punchout-catalog-connection
console data:import punchout-catalog-connection-setup
console data:import punchout-catalog-connection-cart
Verification

Make sure that the configured data are added to the pgw_punchout_catalog_connection, pgw_punchout_catalog_connection_cart, pgw_punchout_catalog_connection_setup tables in the database.

6) Set up Behavior

Set up Punchout Catalogs Workflow

Enable the following behaviors by registering the plugins:

PLUGIN SPECIFICATION PREREQUISITES NAMESPACE
DisallowPunchoutCompanyUserChangePlugin Prevets company user change for logged in punchout catalog customers. None PunchoutCatalog\Client\PunchoutCatalog\Plugin\BusinessOnBehalf.
SingleCompanyUserDatabaseStrategyPreCheckPlugin Disables persistent cart for Single User PunchoutCatalog connection types. None PunchoutCatalog\Client\PunchoutCatalog\Plugin\Quote
ProductBundleCartItemTransformerPlugin Provides functionality to transform bundled items structure during punchout catalog cart transfer. This plugin should be registered only if ProductBundle feature is already present. PunchoutCatalog\Yves\PunchoutCatalog\Plugin\PunchoutCatalog
ImpersonationDetailsCustomerOauthRequestMapperPlugin Maps Punchout impersonation details from CustomerTransfer into access token request. None PunchoutCatalog\Zed\PunchoutCatalog\Communication\Plugin\OauthCompanyUser
ImpersonationDetailsCustomerExpanderPlugin Expands CustomerTransfer with Punchout impersonation details. None PunchoutCatalog\Zed\PunchoutCatalog\Communication\Plugin\OauthCompanyUser

src/Pyz/Client/BusinessOnBehalf/BusinessOnBehalfDependencyProvider.php

<?php

namespace Pyz\Client\BusinessOnBehalf;

use PunchoutCatalog\Client\PunchoutCatalog\Plugin\BusinessOnBehalf\DisallowPunchoutCompanyUserChangePlugin;
use Spryker\Client\BusinessOnBehalf\BusinessOnBehalfDependencyProvider as BaseBusinessOnBehalfDependencyProvider;

class BusinessOnBehalfDependencyProvider extends BaseBusinessOnBehalfDependencyProvider
{
    /**
     * @return \Spryker\Client\BusinessOnBehalfExtension\Dependency\Plugin\CompanyUserChangeAllowedCheckPluginInterface[]
     */
    protected function getCompanyUserChangeAllowedCheckPlugins(): array
    {
        return [
            new DisallowPunchoutCompanyUserChangePlugin(),
        ];
    }
}
Verification

Make sure that you can’t change the company user in your account details when you are in progress of transferred cart creation.

src/Pyz/Client/Quote/QuoteDependencyProvider.php

<?php

namespace Pyz\Client\Quote;

use PunchoutCatalog\Client\PunchoutCatalog\Plugin\Quote\SingleCompanyUserDatabaseStrategyPreCheckPlugin;
use Spryker\Client\Quote\QuoteDependencyProvider as BaseQuoteDependencyProvider;

class QuoteDependencyProvider extends BaseQuoteDependencyProvider
{
    /**
     * @return \Spryker\Client\QuoteExtension\Dependency\Plugin\DatabaseStrategyPreCheckPluginInterface[]
     */
    protected function getDatabaseStrategyPreCheckPlugins(): array
    {
        return [
            new SingleCompanyUserDatabaseStrategyPreCheckPlugin(),
        ];
    }
}
Verification

Make sure that punchout catalogs carts for SingleUser connection types do not appear in spy_quote DB table.

src/Pyz/Yves/PunchoutCatalog/PunchoutCatalogDependencyProvider.php

<?php

namespace Pyz\Yves\PunchoutCatalog;

use PunchoutCatalog\Yves\PunchoutCatalog\Plugin\PunchoutCatalog\ProductBundleCartItemTransformerPlugin;
use PunchoutCatalog\Yves\PunchoutCatalog\PunchoutCatalogDependencyProvider as BasePunchoutCatalogDependencyProvider;

/**
 * @method \PunchoutCatalog\Yves\PunchoutCatalog\PunchoutCatalogConfig getConfig()
 */
class PunchoutCatalogDependencyProvider extends BasePunchoutCatalogDependencyProvider
{
    /**
     * @return \PunchoutCatalog\Yves\PunchoutCatalog\Dependency\Plugin\CartItemTransformerPluginInterface[]
     */
    protected function getCartItemTransformerPlugins(): array
    {
        return [
            new ProductBundleCartItemTransformerPlugin(),
        ];
    }
}
Verification

Make sure that in transferred cart XML bundled product items has childBundleItems section (in case you have Product Bundles feature - otherwise this plugin should not be registered).

src/Pyz/Zed/OauthCompanyUser/OauthCompanyUserDependencyProvider.php

namespace Pyz\Zed\OauthCompanyUser;

use PunchoutCatalog\Zed\PunchoutCatalog\Communication\Plugin\OauthCompanyUser\ImpersonationDetailsCustomerExpanderPlugin;
use PunchoutCatalog\Zed\PunchoutCatalog\Communication\Plugin\OauthCompanyUser\ImpersonationDetailsCustomerOauthRequestMapperPlugin;
use Spryker\Zed\OauthCompanyUser\OauthCompanyUserDependencyProvider as SprykerOauthCompanyUserDependencyProvider;

class OauthCompanyUserDependencyProvider extends SprykerOauthCompanyUserDependencyProvider
{
    /**
     * @return \Spryker\Zed\OauthCompanyUserExtension\Dependency\Plugin\CustomerOauthRequestMapperPluginInterface[]
     */
    protected function getCustomerOauthRequestMapperPlugins(): array
    {
        return [
            new ImpersonationDetailsCustomerOauthRequestMapperPlugin(),
        ];
    }

    /**
     * @return \Spryker\Zed\OauthCompanyUserExtension\Dependency\Plugin\CustomerExpanderPluginInterface[]
     */
    protected function getCustomerExpanderPlugins(): array
    {
        return [
            new ImpersonationDetailsCustomerExpanderPlugin(),
        ];
    }
}
Verification

Make sure that when you chose the supplier for transferred cart in ERP, and redirected to the shop - you are logged in.

Install feature frontend

Prerequisites

To start feature integration, overview and install the necessary features:

NAME VERSION
Cart 202009.0
Spryker Core 202009.0

1) Set up Widgets

Register the following global widgets:

PLUGIN DESCRIPTION PREREQUISITES NAMESPACE
PunchoutCatalogCheckoutButtonsWidget Displays Transfer Cart and Cancel Cart & Return buttons on the cart page. None PunchoutCatalog\Yves\PunchoutCatalog\Widget

src/Pyz/Yves/ShopApplication/ShopApplicationDependencyProvider.php

<?php

namespace Pyz\Yves\ShopApplication;

use PunchoutCatalog\Yves\PunchoutCatalog\Widget\PunchoutCatalogCheckoutButtonsWidget;
use SprykerShop\Yves\ShopApplication\ShopApplicationDependencyProvider as SprykerShopApplicationDependencyProvider;

class ShopApplicationDependencyProvider extends SprykerShopApplicationDependencyProvider
{
    /**
     * @return string[]
     */
    protected function getGlobalWidgets(): array
    {
        return [
            PunchoutCatalogCheckoutButtonsWidget::class,
        ];
    }
}

Adjust codebase to register PunchoutCatalogCheckoutButtonsWidget widget.

src/Pyz/Yves/CartPage/CartPageDependencyProvider.php

<?php

namespace Pyz\Yves\CartPage;

use SprykerShop\Yves\CartPage\CartPageDependencyProvider as SprykerCartPageDependencyProvider;
use Spryker\Yves\Kernel\Container;
use SprykerShop\Yves\CartPage\Dependency\Client\CartPageToCustomerClientBridge;

class CartPageDependencyProvider extends SprykerCartPageDependencyProvider
{
    public const CLIENT_CUSTOMER = 'CLIENT_CUSTOMER';

    /**
     * @param \Spryker\Yves\Kernel\Container $container
     *
     * @return \Spryker\Yves\Kernel\Container
     */
    public function provideDependencies(Container $container)
    {
        $container = $this->addCustomerClient($container);

        return $container;
    }

    /**
     * @param \Spryker\Yves\Kernel\Container $container
     *
     * @return \Spryker\Yves\Kernel\Container
     */
    protected function addCustomerClient(Container $container)
    {
        $container[static::CLIENT_CUSTOMER] = function (Container $container) {
            return $container->getLocator()->customer()->client();
        };

        return $container;
    }
}

src/Pyz/Yves/CartPage/CartPageFactory.php

<?php

namespace Pyz\Yves\CartPage;

use SprykerShop\Yves\CartPage\CartPageFactory as SprykerCartPageFactory;
use SprykerShop\Yves\CartPage\Dependency\Client\CartPageToCustomerClientInterface;

class CartPageFactory extends SprykerCartPageFactory
{
    /**
     * @return \SprykerShop\Yves\CartPage\Dependency\Client\CartPageToCustomerClientInterface
     */
    public function getCustomerClient(): CartPageToCustomerClientInterface
    {
        return $this->getProvidedDependency(CartPageDependencyProvider::CLIENT_CUSTOMER);
    }
}

src/Pyz/Yves/CartPage/Controller/CartController.php

namespace Pyz\Yves\CartPage\Controller;

use SprykerShop\Yves\CartPage\Controller\CartController as SprykerCartController;
use SprykerShop\Yves\ShopApplication\Controller\AbstractController;

/**
 * @method \SprykerShop\Yves\CartPage\CartPageFactory getFactory()
 */
class CartController extends SprykerCartController
{
    /**
     * @param array|null $selectedAttributes
     *
     * @return array
     */
    protected function executeIndexAction(?array $selectedAttributes): array
    {
        $data = parent::executeIndexAction($selectedAttributes);

        $data['customer'] = $$this->getFactory()
            ->getCustomerClient()
            ->getCustomer();

        return $data;
    }

src/Pyz/Yves/CartPage/Theme/default/components/molecules/cart-summary/cart-summary.twig

{% define data = {
    customer: required,
} %}

{% set canProceedToCheckout = data.cart.items is not empty
    and data.isQuoteValid
    and (not is_granted('ROLE_USER') or can('WriteSharedCartPermissionPlugin', data.cart.idQuote))
    and (not is_granted('ROLE_USER')
        or can('WriteSharedCartPermissionPlugin', data.cart.idQuote)
        or data.customer.punchoutCatalogImpersonationDetails.is_punchout
    )
%}
    {% if canProceedToCheckout %}
        {% if data.customer.punchoutCatalogImpersonationDetails.is_punchout is defined %}
            <hr>
            {% widget 'PunchoutCatalogCheckoutButtonsWidget' args [data.customer] %}{% endwidget %}
        {% else %}
            {% widget 'ProceedToCheckoutButtonWidget' args [data.cart] %}
                 {% block body %}
                     <hr>
                     {{ parent() }}
                 {% endblock %}
            {% endwidget %}
        {% endif %}
    {% endif %}

src/Pyz/Yves/CartPage/Theme/default/templates/page-layout-cart/page-layout-cart.twig

{% define data = {
    customer: _view.customer,
} %}

  {% block cartSummary %}
     {% include molecule('cart-summary', 'CartPage') with {
         data: {
             customer: data.customer,
         },
     } only %}
  {% endblock %}

Run the following command to enable Javascript and CSS changes:

console frontend:yves:build
Verification

Make sure that you see Transfer Cart and Cancel Cart & Return buttons on the cart page for PunchoutCatalog carts.

2) Enable Controllers

Register the following plugin:

PLUGIN DESCRIPTION PREREQUISITES NAMESPACE
PunchoutCatalogControllerProvider Provides routes used in PunchoutCatalogCheckoutButtonsWidget. None PunchoutCatalog\Yves\PunchoutCatalog\Plugin\Provider

src/Pyz/Yves/ShopApplication/YvesBootstrap.php

<?php

namespace Pyz\Yves\ShopApplication;

use PunchoutCatalog\Yves\PunchoutCatalog\Plugin\Provider\PunchoutCatalogControllerProvider;
use SprykerShop\Yves\ShopApplication\YvesBootstrap as SprykerYvesBootstrap;

class YvesBootstrap extends SprykerYvesBootstrap
{
    /**
     * @param bool|null $isSsl
     *
     * @return \SprykerShop\Yves\ShopApplication\Plugin\Provider\AbstractYvesControllerProvider[]
     */
    protected function getControllerProviderStack($isSsl)
    {
        return [
            new PunchoutCatalogControllerProvider($isSsl),
        ];
    }
}
Verification

Make sure that when you click Transfer Cart button on a cart page, it redirects you back to the connected ERP system.

3) Set up Behavior

Set up Punchout Catalogs Workflow

src/Pyz/Yves/CustomerPage/Controller/AccessTokenController.php

<?php

namespace Pyz\Yves\CustomerPage\Controller;

use SprykerShop\Yves\CustomerPage\Controller\AccessTokenController as SprykerAccessTokenController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;

/**
 * @method \SprykerShop\Yves\CustomerPage\CustomerPageFactory getFactory()
 */
class AccessTokenController extends SprykerAccessTokenController
{
    /**
     * @param string $token
     * @param \Symfony\Component\HttpFoundation\Request|null $request
     *
     * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
     *
     * @return \Symfony\Component\HttpFoundation\RedirectResponse
     */
    public function indexAction(string $token, ?Request $request = null): RedirectResponse
    {
        $customerResponseTransfer = $this
            ->getFactory()
            ->getCustomerClient()
            ->getCustomerByAccessToken($token);

        if (!$customerResponseTransfer->getIsSuccess()) {
            $this->addErrorMessage(static::GLOSSARY_KEY_INVALID_ACCESS_TOKEN);
            throw new AccessDeniedHttpException();
        }

        if ($this->isLoggedInCustomer()) {
            $this->getFactory()
                ->getCustomerClient()
                ->logout();
        }

        $customerTransfer = $customerResponseTransfer->getCustomerTransfer();
        $token = $this->getFactory()->createUsernamePasswordToken($customerTransfer);

        $this->getFactory()
            ->createCustomerAuthenticator()
            ->authenticateCustomer($customerTransfer, $token);

        $returnRoute = $this->getReturnRoute($request);

        return $this->redirectResponseInternal($returnRoute);
    }

    /**
     * @param \Symfony\Component\HttpFoundation\Request|null $request
     *
     * @return string
     */
    protected function getReturnRoute(?Request $request = null): string
    {
        if ($request === null) {
            return static::ROUTE_CUSTOMER_OVERVIEW;
        }

        $returnRoute = $request->query->get('returnUrl');

        return empty($returnRoute) ? static::ROUTE_CUSTOMER_OVERVIEW : $returnRoute;
    }
}
Verification

Make sure that when you came to shop from ERP it logins you by the proper user, according to your connection Login Mode preferences, even if previously you were logged in by another customer.