Skip to main content

cXML Response Generator

The CxmlConnectorResponseGenerator provides three methods: one for the login handshake, one for error responses, and one for the actual cart transfer.


generatePunchoutSetupResponse()​

public function generatePunchoutSetupResponse(
string $cxmlString,
string $startUrl,
SalesChannelContext $context
): string

Generates the cXML response to the procurement system's PunchOutSetupRequest. It contains a StartPage URL to which the procurement system redirects the buyer's browser.

Response structure:

<cXML payloadID="..." timestamp="..." xml:lang="en-US">
<Response>
<Status code="200" text="OK"/>
<PunchOutSetupResponse>
<StartPage>
<URL>https://shop.example.com/AgiqonCxmlEntry/auth/...</URL>
</StartPage>
</PunchOutSetupResponse>
</Response>
</cXML>

generateInvalidPunchoutSetupResponse()​

public function generateInvalidPunchoutSetupResponse(
SimpleXMLElement $requestXml,
int $statusCode,
string $text,
string $message
): string

Generates an error response (e.g. 400 Bad Request, 401 Unauthorized) when login fails.


generateCxmlPunchOutOrderMessage()​

public function generateCxmlPunchOutOrderMessage(
ConnectorSession $session,
CxmlSystemEntity $cxmlSystem,
Cart $cart,
SalesChannelContext $context
): string

The main method for the cart transfer. It generates the full cXML PunchOutOrderMessage body.

Process​

  1. Build the header — From and To are swapped per the cXML convention (the original To becomes the response From and vice versa)
  2. Insert BuyerCookie from session additionalFields
  3. PunchOutOrderMessageHeader with operationAllowed, quoteStatus="final", and total price
  4. Optionally: append shipping (when attachShipping is enabled)
  5. Optionally: append tax (when attachTax is enabled)
  6. Iterate line items → find matching resolver for each → recursively render field tree
  7. Fire CxmlResponseGenerationEvent → XML can still be modified
  8. Clean output (remove line breaks and whitespace between tags)

Price configuration​

System settingPrice used
isTotalPriceNet() = trueCart::getPrice()::getNetPrice()
isTotalPriceNet() = falseCart::getPrice()::getTotalPrice()

The number of decimal places is controlled by the system's priceDigits setting.

Hierarchical field tree​

cXML fields can be nested (parent/child relationship). The generator builds an internal field tree and renders it recursively as XML elements. The order within each level is determined by the fields' position attribute.

XML attributes​

Fields can carry an XML attribute in addition to a text value:

  • Standard attribute — set directly on the element
  • Namespace attribute — set with the cXML namespace http://xml.cxml.org/schemas/cXML/1.2.040/cXML.dtd

The attribute value is either resolved from a DataField or configured as a static string.


CxmlResponseGenerationEvent​

Just before the XML document is serialised, the generator fires:

EventEvent nameWhat can be changed?
CxmlResponseGenerationEventagiqon_connector.cxml.response.generationThe complete SimpleXMLElement object

Example:

use AgiqonConnector\Connector\System\Cxml\Event\CxmlResponseGenerationEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use SimpleXMLElement;

#[AsEventListener(event: CxmlResponseGenerationEvent::EVENT_NAME)]
final class MyCxmlResponseListener
{
public function __invoke(CxmlResponseGenerationEvent $event): void
{
$xml = $event->getCxml();

// Add custom XML elements or modify existing ones
// $event->setCxml($modifiedXml);
}
}
info

The event receives the fully built SimpleXMLElement. Use setCxml() to replace the entire document with a custom instance.