Tracking Page Business Rules
This document outlines the business logic and rules for the order tracking system implemented in the theme repository.
Overviewโ
The order tracking system displays order status, shipment tracking, and delivery information to customers. It integrates data from:
- Shopify Admin API (order data, fulfillments, refunds)
- Aftership API (carrier tracking, delivery estimates)
- Platform API (
/v1/tracking/get-order-with-shipments)
Order Status Determinationโ
Status Priority Hierarchyโ
The system uses a waterfall logic where higher-priority conditions override lower ones:
1. ORDER-LEVEL STATES (Highest Priority)
- Order canceled โ "Canceled"
- Order refunded โ "Refunded"
- Exception checkpoint exists โ "Exception"
2. SHIPMENT-LEVEL REFUND STATES
- All line items returned โ "Returned"
- All line items canceled โ "Canceled"
- Some line items refunded:
* All refunded โ "Refunded"
* Partial refund โ "Partially Refunded"
3. AFTERSHIP TRACKING STATES
- Has Aftership status (not Delivered) โ Use Aftership status
- Delivered with date โ "Delivered on {date}"
- Fulfilled but no Aftership โ "Delivered" (expired tracking)
4. PRODUCTION TIMELINE (MTO Only)
- Before production start โ "Ordered"
- After production start, no transit scan โ "In Production"
- Has transit scan โ "In Transit"
Key Ruleโ
Financial states (refunds/cancellations) always override tracking states, even if Aftership shows "Delivered".
Product Type Detectionโ
Made-to-Order (MTO)โ
const isMTO = lineItems.some(item =>
item.properties.find(prop => prop.name === "_MADE-TO-ORDER")
)
Preorderโ
const isPREORDER = lineItems.some(item =>
item.properties.find(prop =>
prop.name === "PREORDER" || prop.name === "_PREORDER"
)
)
Ready-to-Ship (RTS)โ
const isRTS = !isMTO && !isPREORDER
Production Timeline Logic (MTO Only)โ
See Production Timeline for detailed production timeline documentation including:
- Timeline selection based on
_PRODUCTION_DAYSline item property - Predefined timeline configurations (49 and 56 days)
- Custom timeline calculation formula
- Timeline phases and messaging
Expected Delivery Date Calculationโ
Priority Cascade (First Match Wins)โ
1. PREORDER DATE
- Extract from line item property value
- Format: MM-DD-YYYY in "_PREORDER" or "PREORDER" property
- Uses max date if multiple preorder items
- Display: "until" format
2. MTO SHIPPING LINE CODE
- Extract weeks from shipping_line.code (e.g., "4 weeks")
- Calculate: order.processed_at + (weeks ร 7 days)
- Display: "until" format
3. FIRST ESTIMATED DELIVERY
- shipment.first_estimated_delivery (manual override)
- Can be "specific" or "range"
4. CUSTOM ESTIMATED DELIVERY
- shipment.custom_estimated_delivery (manual override)
- Can be "specific" or "range"
5. AFTERSHIP ESTIMATED DELIVERY DATE
- shipment.aftership_estimated_delivery_date
- From carrier API
- Can be "specific" or "range"
6. LATEST ESTIMATED DELIVERY
- shipment.latest_estimated_delivery (updated estimate)
- Can be "specific" or "range"
7. EXPECTED DELIVERY
- shipment.expected_delivery (fallback)
- Always "specific" format
Display Formatsโ
- Specific: "Expected on Tuesday, April 17"
- Range: "Expected between Monday, April 15 - Friday, April 20"
- Until: "Expected on Friday, April 20"
- Delivered: "Delivered Tuesday, April 17" (overrides all formats)
When NOT to Show Expected Dateโ
Don't display expected delivery date if:
- Status is: Delivered, Out for Delivery, Available for Pickup, Attempt Fail
- Order state: Expired, Canceled, Refunded
- Status is Exception
- RTS order without real carrier scans (prevents false promises)
Real Scan Detectionโ
Purposeโ
Determines if a shipment has actual carrier scans vs. just label creation.
Real Scan Tagsโ
const REAL_SCAN_TAGS = [
'InTransit',
'OutForDelivery',
'Delivered',
'AvailableForPickup',
'AttemptFail',
'Exception'
];
const hasRealScan = shipment.checkpoints.some(cp =>
REAL_SCAN_TAGS.includes(cp?.tag)
);
Business Rule: RTS Without Real Scansโ
For Ready-to-Ship orders without real carrier scans:
- Don't show expected delivery date
- Don't show detailed tracking information
- Status remains "Ordered" until carrier physically scans package
Why: Prevents misleading customers with delivery dates when carrier has only received shipping label info but hasn't actually received the package.
Refund Display Logicโ
Line Item Levelโ
// Show strikethrough price + "(Refunded)" if:
if (
totalRefundAmount > 0 &&
refund_line_items.some(refundItem =>
refundItem.line_item_id === lineItem.id &&
refundItem.subtotal > 0
)
) {
display: "<strike>$XX.XX</strike> (Refunded)"
}
Order Summary Levelโ
// Calculate total refunded amount
totalRefundAmount = order.refunds
.flatMap(refund => refund.transactions)
.filter(tx => tx.status === "success")
.reduce((sum, tx) => sum + Number(tx.amount), 0);
// Adjust order total
displayTotal = order.total_price - totalRefundAmount;
Status by Refund Typeโ
// Determine which line items in THIS shipment are refunded
refundedInShipment = allRefundedLineItems.filter(refundItem =>
shipment.line_items.some(shipItem =>
shipItem.id === refundItem.line_item_id
)
);
// All items refunded
if (refundedInShipment.length === shipment.line_items.length) {
if (all have restock_type === "return") {
status = "Returned"
} else {
status = "Refunded"
}
}
// Some items refunded
else if (refundedInShipment.length > 0) {
status = "Partially Refunded"
}
Business Rule: Partial refunds can coexist with other statuses. A shipment can show "Partially Refunded" while also displaying "Delivered" if tracking confirms delivery.
Order Cancellationโ
Self-Service Cancellation Windowโ
const hoursPassedSinceOrdered = Math.abs(
differenceInHours(now, order.processedAt)
);
const canCancel =
hoursPassedSinceOrdered < 1 &&
!['fulfilled', 'shipped', 'in_transit'].includes(fulfillmentStatus) &&
!['paid', 'refunded', 'partially_refunded'].includes(financialStatus);
Business Rulesโ
- 1-hour window for customer self-service cancellation
- After 1 hour, customer must contact support
- Cannot cancel if already fulfilled/shipped
- Cannot cancel if already paid/refunded
Business Context: Balances customer flexibility with fulfillment efficiency. Prevents cancellations after warehouse has already started processing.
Return Eligibilityโ
Display Ruleโ
// Show "Return Items" button if:
const canReturn = orderStatus.canReturn; // from Aftership data
if (canReturn) {
display button linking to "https://birdygrey.happyreturns.com/"
}
Determined Byโ
- Order is delivered
- Within return window (typically 30 days from delivery)
- Not final sale items (checked via line item
_is_final_saleproperty)
Final Sale Itemsโ
Detectionโ
const isFinalSale = lineItem.properties.some(prop =>
(prop.name === "_is_final_sale" || prop.name === "is_final_sale") &&
prop.value === "true"
);
Displayโ
If final sale:
- Show red "Final Sale" badge on line item
- Affects return eligibility (cannot return)
Key Business Decisions Summaryโ
-
Financial states override tracking states - Refunds/cancellations are more important than delivery status
-
MTO products get production timeline UI - Sets proper expectations for made-to-order items with transparent progress updates
-
RTS without scans stays "Ordered" - Prevents false delivery promises when carrier hasn't physically received package
-
Multiple manual override points - Allows CS team to manually set delivery dates via first/custom/latest estimated delivery fields
-
Privacy by default for guests - Only show full PII to verified customers; guests see limited info
-
Progressive production messaging - Keeps customers engaged during long MTO timelines with meaningful updates
-
1-hour cancellation window - Balances customer flexibility with fulfillment efficiency
-
Filter confusing tracking events - Only show meaningful checkpoints to customers (no China scans, customs events, etc.)
-
Handle partial refunds gracefully - Show accurate item-level refund state while maintaining overall order context
-
Expired tracking = Delivered - Prevents "stuck" orders in tracking UI for old or manually fulfilled orders
Related Documentationโ
- UI & Display - Tracking page UI and general display logic
- Production Timeline - MTO production timeline logic
Related Filesโ
Hydrogen Storefrontโ
app/routes/account.orders.tsx- Fetches order data with Aftership integrationapp/components/Order/order.component.tsx- Order listing with tracking linkapp/lib/account/utils.ts- Status calculation helpers
Theme Repositoryโ
See UI & Display - Related Files for theme-specific files.
API Integrationโ
Platform API Endpointโ
GET {platformUrl}/v1/tracking/get-order-with-shipments?{input}&email={email}
Environment Detection:
- Production:
platform.birdygrey.com(when store domain includes "birdygrey" or is "birdygrace.myshopify.com") - Staging:
platform.birdystaging.com(all other stores)
Input Parameter:
id={orderId}ORnumber={orderNumber}- Requires
email={customerEmail}for guest access
Response: Complete order object including:
- Shopify order data (line items, fulfillments, refunds)
- Aftership shipment data (tracking, checkpoints, estimates)
- Enriched fields (rush fees, production flags)