Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/actions/submit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { publishEvent } from '../../events.js';
import makeContext from '../../context.js';
import { createProductRegistration, queryOrder } from '../../ebs.js';
import { proxyFetch } from '../../proxy.js';
import { deriveOrderStatus } from '../../order-status.js';

const MAX_PAYLOAD_SIZE = 16_000; // 16KB

Expand Down Expand Up @@ -233,6 +234,7 @@ async function handleOrderStatus(ctx, formId, data) {
body.outcome = 'Partially Cancelled';
}
}
body.order.status = deriveOrderStatus(lineItems);

// remove PII from data
delete body.order?.customer;
Expand Down
49 changes: 49 additions & 0 deletions src/order-status.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Derive the customer-facing order status from EBS line items.
*
* This intentionally mirrors Magento's Vitamix_OrderStatus helper:
* warranty/service lines (UnitOfMeasure != Each) are excluded, cancelled
* lines are removed from the active-item denominator, and the final status
* is selected in shipped -> processed -> received order.
*
* @param {object[]} lineItems - Transformed EBS line items
* @returns {string} Status key for the storefront
*/
export function deriveOrderStatus(lineItems) {
const items = (Array.isArray(lineItems) ? lineItems : []).filter(
(item) => item?.unitOfMeasure === 'Each',
);

let received = 0;
let processed = 0;
let cancelled = 0;
let shipped = 0;

items.forEach((item) => {
const status = String(item?.status ?? '').toUpperCase();
const quantity = item?.quantity;

if (status === 'ENTERED') {
received += 1;
} else if (['BOOKED', 'AWAITINGSHIPPING', 'PICKED'].includes(status)) {
processed += 1;
} else if (status === 'CLOSED') {
if (quantity != null && Number(quantity) === 0) {
cancelled += 1;
} else {
shipped += 1;
}
} else if (status === 'SHIPPED') {
shipped += 1;
}
});

const activeItemCount = items.length - cancelled;

if (cancelled > 0 && cancelled === items.length) return 'cancelled';
if (shipped === activeItemCount) return 'shipped';
if (shipped > 0) return 'partiallyShipped';
if (processed === activeItemCount) return 'processed';
if (processed + received === activeItemCount) return 'received';
return 'unavailable';
}
42 changes: 42 additions & 0 deletions test/order-status.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { deriveOrderStatus } from '../src/order-status.js';

describe('deriveOrderStatus', () => {
test('ignores non-Each service lines', () => {
expect(deriveOrderStatus([
{ unitOfMeasure: 'Years', status: 'Entered', quantity: '1' },
])).toBe('shipped');
});

test.each([
['Entered', 'received'],
['Booked', 'processed'],
['AwaitingShipping', 'processed'],
['Picked', 'processed'],
['Shipped', 'shipped'],
['Closed', 'shipped'],
])('maps %s to %s', (status, expected) => {
expect(deriveOrderStatus([
{ unitOfMeasure: 'Each', status, quantity: '1' },
])).toBe(expected);
});

test('treats Closed quantity zero as cancelled', () => {
expect(deriveOrderStatus([
{ unitOfMeasure: 'Each', status: 'Closed', quantity: '0' },
])).toBe('cancelled');
});

test('evaluates remaining items after cancelled items are excluded', () => {
expect(deriveOrderStatus([
{ unitOfMeasure: 'Each', status: 'Closed', quantity: '0' },
{ unitOfMeasure: 'Each', status: 'Booked', quantity: '1' },
])).toBe('processed');
});

test('returns partiallyShipped when some active items shipped', () => {
expect(deriveOrderStatus([
{ unitOfMeasure: 'Each', status: 'Shipped', quantity: '1' },
{ unitOfMeasure: 'Each', status: 'Booked', quantity: '1' },
])).toBe('partiallyShipped');
});
});
24 changes: 24 additions & 0 deletions test/submit.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,30 @@ describe('submit action', () => {
expect(result.body.order.delivery).toHaveLength(1);
});

test('returns the Magento-compatible status derived from EBS line items', async () => {
const bookedBody = {
Response: {
'@_Id': 'booked-order',
'@_Outcome': 'Success',
'@_Succeeded': 'true',
'Order': {
'@_Key': 'om-booked',
'LineItem': [
{ '@_UnitOfMeasure': 'Each', '@_Status': 'Booked', '@_Quantity': '1' },
{ '@_UnitOfMeasure': 'Years', '@_Status': 'Entered', '@_Quantity': '1' },
],
},
},
};

mockMakeContext.mockResolvedValue(makeOrderCtx('om-booked'));
mockQueryOrder.mockResolvedValue({ status: 200, body: bookedBody });

const result = await main({});
expect(result.body.order.status).toBe('processed');
expect(result.body.order).not.toHaveProperty('lineItem');
});

test('omits PII fields from response', async () => {
mockMakeContext.mockResolvedValue(makeOrderCtx());
mockQueryOrder.mockResolvedValue({ status: 200, body: successBody });
Expand Down
Loading