Skip to content

Search is only available in production builds. Try building and previewing the site to test it out locally.

Purchase Order Events

The Purchase Order drop-in emits 5 events to the event bus, allowing you to track and respond to purchase order state changes, order placement, and permission updates.

Version: 1.0.0-beta1

Available events

Event NameDescription
auth/permissionsEmitted when user permissions are updated or refreshed
order/dataEmitted when order data associated with a purchase order changes
purchase-order/dataEmitted when purchase order data is loaded or updated
purchase-order/placedEmitted when a purchase order is successfully placed
purchase-order/refreshEmitted to trigger a refresh of purchase order data

Event details

auth/permissions

Emitted when user permissions related to purchase orders are updated or need to be refreshed.

Event payload

{
eventType: 'auth/permissions',
data: {
permissions: string[] // Array of permission codes
}
}

When triggered

  • After user logs in
  • After company role changes
  • After approval rule permissions are modified
  • After company context switches

Example

import { events } from '@dropins/tools/event-bus.js';
events.on('auth/permissions', (payload) => {
console.log('Permissions updated:', payload.data.permissions);
// Check for specific permissions
const canCreatePO = payload.data.permissions.includes('Magento_PurchaseOrder::create');
const canApprovePO = payload.data.permissions.includes('Magento_PurchaseOrder::approve');
// Update UI based on permissions
updatePurchaseOrderActions(canCreatePO, canApprovePO);
});

Usage scenarios

  • Show/hide purchase order action buttons
  • Enable/disable approval workflow features
  • Update navigation menu items
  • Conditionally render UI components

order/data

Emitted when standard order data associated with a purchase order changes or is loaded.

Event payload

{
eventType: 'order/data',
data: OrderModel // Order data object
}

When triggered

  • After a purchase order is converted to an order
  • When loading order confirmation details
  • After order status updates

Example

import { events } from '@dropins/tools/event-bus.js';
events.on('order/data', (payload) => {
console.log('Order data loaded:', payload.data);
// Display order confirmation
showOrderConfirmation(payload.data);
// Track conversion
trackPurchaseOrderConversion(payload.data.orderNumber);
});

Usage scenarios

  • Display order confirmation after PO placement
  • Update order tracking information
  • Sync order data with external systems
  • Trigger post-purchase workflows

purchase-order/data

Emitted when purchase order data is loaded, updated, or changes state.

Event payload

{
eventType: 'purchase-order/data',
data: PurchaseOrderModel // Purchase order data
}

When triggered

  • After loading a purchase order
  • After approving a purchase order
  • After rejecting a purchase order
  • After canceling a purchase order
  • After adding comments to a purchase order
  • After updating purchase order status

Example

import { events } from '@dropins/tools/event-bus.js';
events.on('purchase-order/data', (payload) => {
const po = payload.data;
console.log('Purchase order updated:', po.number, po.status);
// Update the UI to reflect current status
updatePurchaseOrderStatus(po.status);
// Show approval flow if needed
if (po.requiresApproval) {
displayApprovalFlow(po.approvalFlow);
}
});

Usage scenarios

  • Refresh purchase order details view
  • Update purchase order lists
  • Display approval flow progress
  • Show status-specific actions
  • Update cached purchase order data

purchase-order/placed

Emitted when a purchase order is successfully placed from the cart.

Event payload

{
eventType: 'purchase-order/placed',
data: {
purchaseOrderNumber: string,
requiresApproval: boolean,
status: string
}
}

When triggered

  • After successfully calling placePurchaseOrder()
  • After converting a cart to a purchase order

Example 1: Basic purchase order placement

import { events } from '@dropins/tools/event-bus.js';
events.on('purchase-order/placed', (payload) => {
const { purchaseOrderNumber, requiresApproval, status } = payload.data;
console.log(`Purchase order ${purchaseOrderNumber} placed with status: ${status}`);
// Show appropriate confirmation message
if (requiresApproval) {
showMessage('Purchase order submitted for approval');
redirectToApprovalStatus(purchaseOrderNumber);
} else {
showMessage('Purchase order placed successfully');
redirectToOrderConfirmation(purchaseOrderNumber);
}
// Track analytics
trackPurchaseOrderPlacement(purchaseOrderNumber, requiresApproval);
});

Example 2: Complete checkout workflow with notifications

import { events } from '@dropins/tools/event-bus.js';
import { placePurchaseOrder } from '@dropins/storefront-purchase-order/api.js';
async function completePurchaseOrderCheckout(cartId) {
try {
// Show checkout processing
showCheckoutModal('Processing your purchase order...');
// Place the purchase order
await placePurchaseOrder(cartId);
// Listen for successful placement
events.once('purchase-order/placed', async (payload) => {
const { purchaseOrderNumber, requiresApproval, status } = payload.data;
// Close processing modal
hideCheckoutModal();
// Clear cart UI
clearCartDisplay();
// Show success modal with details
if (requiresApproval) {
showSuccessModal({
title: 'Purchase Order Submitted',
message: `Your purchase order #${purchaseOrderNumber} has been submitted for approval.`,
details: [
`Status: Pending Approval`,
`You will be notified when it's reviewed.`,
`Track your order in the Purchase Orders section.`
],
primaryAction: {
label: 'View Purchase Order',
onClick: () => window.location.href = `/purchase-orders/${purchaseOrderNumber}`
},
secondaryAction: {
label: 'Continue Shopping',
onClick: () => window.location.href = '/products'
}
});
// Send notification email
await sendNotification({
type: 'purchase-order-submitted',
purchaseOrderNumber,
approvers: payload.data.approvers
});
} else {
showSuccessModal({
title: 'Order Placed Successfully',
message: `Your purchase order #${purchaseOrderNumber} has been placed.`,
details: [
`Status: ${status}`,
`You will receive a confirmation email shortly.`
],
primaryAction: {
label: 'View Order',
onClick: () => window.location.href = `/orders/${purchaseOrderNumber}`
}
});
}
// Track conversion
trackConversion({
type: 'purchase-order',
orderNumber: purchaseOrderNumber,
requiresApproval,
value: payload.data.total,
currency: payload.data.currency
});
// Update user's PO history count
incrementPurchaseOrderCount();
});
} catch (error) {
hideCheckoutModal();
showErrorModal({
title: 'Failed to Place Purchase Order',
message: error.message || 'An error occurred while processing your order.',
action: {
label: 'Try Again',
onClick: () => completePurchaseOrderCheckout(cartId)
}
});
console.error('Purchase order placement error:', error);
}
}

Example 3: Multi-approval workflow dashboard

import { events } from '@dropins/tools/event-bus.js';
// Dashboard for tracking all purchase orders
class PurchaseOrderDashboard {
constructor() {
this.pendingOrders = [];
this.completedOrders = [];
// Listen for new purchase orders
events.on('purchase-order/placed', this.handleNewOrder.bind(this));
events.on('purchase-order/data', this.handleOrderUpdate.bind(this));
this.init();
}
async init() {
await this.loadExistingOrders();
this.render();
}
handleNewOrder(payload) {
const { purchaseOrderNumber, requiresApproval, status } = payload.data;
const order = {
number: purchaseOrderNumber,
status: status,
requiresApproval,
placedAt: new Date(),
...payload.data
};
if (requiresApproval) {
this.pendingOrders.unshift(order);
// Show real-time notification
this.showNotificationBanner({
type: 'info',
message: `New PO #${purchaseOrderNumber} awaiting approval`,
action: () => this.viewOrder(purchaseOrderNumber)
});
// Play notification sound
this.playNotificationSound();
// Update pending count badge
this.updatePendingBadge(this.pendingOrders.length);
} else {
this.completedOrders.unshift(order);
}
// Refresh dashboard display
this.render();
}
handleOrderUpdate(payload) {
const updatedOrder = payload.data;
// Remove from pending if approved/rejected
if (['approved', 'rejected', 'canceled'].includes(updatedOrder.status)) {
this.pendingOrders = this.pendingOrders.filter(
o => o.number !== updatedOrder.number
);
this.completedOrders.unshift(updatedOrder);
this.updatePendingBadge(this.pendingOrders.length);
}
this.render();
}
render() {
document.querySelector('#pending-orders').innerHTML =
this.renderOrderList(this.pendingOrders, 'pending');
document.querySelector('#completed-orders').innerHTML =
this.renderOrderList(this.completedOrders, 'completed');
}
renderOrderList(orders, type) {
if (orders.length === 0) {
return `<div class="empty-state">No ${type} purchase orders</div>`;
}
return orders.map(order => `
<div class="order-card" data-order="${order.number}">
<div class="order-header">
<span class="order-number">#${order.number}</span>
<span class="order-status status-${order.status}">${order.status}</span>
</div>
<div class="order-details">
<span>Total: $${order.total}</span>
<span>Date: ${formatDate(order.placedAt)}</span>
</div>
</div>
`).join('');
}
showNotificationBanner(options) {
// Show slide-in notification
const banner = document.createElement('div');
banner.className = `notification-banner notification-${options.type}`;
banner.innerHTML = `
<span>${options.message}</span>
<button onclick="this.parentElement.remove()">×</button>
`;
if (options.action) {
banner.onclick = options.action;
}
document.body.appendChild(banner);
setTimeout(() => banner.remove(), 5000);
}
playNotificationSound() {
const audio = new Audio('/sounds/notification.mp3');
audio.play().catch(() => {});
}
updatePendingBadge(count) {
const badge = document.querySelector('.pending-count-badge');
if (badge) {
badge.textContent = count;
badge.style.display = count > 0 ? 'block' : 'none';
}
}
viewOrder(orderNumber) {
window.location.href = `/purchase-orders/${orderNumber}`;
}
async loadExistingOrders() {
// Load existing orders from API
const { pendingOrders, completedOrders } = await fetchPurchaseOrders();
this.pendingOrders = pendingOrders;
this.completedOrders = completedOrders;
}
}
// Initialize dashboard
const dashboard = new PurchaseOrderDashboard();

Usage scenarios

  • Display success confirmation with order details
  • Redirect to appropriate success page (approval vs. direct order)
  • Clear shopping cart after successful placement
  • Send email notifications to approvers
  • Track analytics and conversion events
  • Update purchase order history and counts
  • Show real-time notifications for new orders
  • Update dashboard widgets and badges
  • Trigger approval workflow notifications
  • Log purchase order creation for audit
  • Update budget tracking systems
  • Sync with ERP/accounting systems

purchase-order/refresh

Emitted to signal that purchase order data should be refreshed from the server.

Event payload

{
eventType: 'purchase-order/refresh',
data: {
purchaseOrderId?: string // Optional specific PO to refresh
}
}

When triggered

  • After approval rule changes
  • After permission updates
  • On user request (manual refresh)
  • After significant state changes

Example

import { events } from '@dropins/tools/event-bus.js';
// Emit refresh event
events.emit('purchase-order/refresh', {
purchaseOrderId: 'PO123456'
});
// Listen for refresh requests
events.on('purchase-order/refresh', async (payload) => {
if (payload.data.purchaseOrderId) {
// Refresh specific purchase order
await refreshPurchaseOrder(payload.data.purchaseOrderId);
} else {
// Refresh all purchase orders
await refreshAllPurchaseOrders();
}
});

Usage scenarios

  • Force reload after external updates
  • Implement pull-to-refresh functionality
  • Sync data after background changes
  • Refresh after approval rule modifications

Listening to events

All Purchase Order events are emitted through the centralized event bus. Subscribe to events using the events.on() method:

import { events } from '@dropins/tools/event-bus.js';
// Listen to purchase order lifecycle events
events.on('purchase-order/placed', handlePurchaseOrderPlaced);
events.on('purchase-order/data', handlePurchaseOrderData);
events.on('purchase-order/refresh', handleRefreshRequest);
// Listen to permission changes
events.on('auth/permissions', handlePermissionUpdate);
// Remove listeners when done
events.off('purchase-order/placed', handlePurchaseOrderPlaced);