\s*Total:/i) ||
+ html.match(/order with\s+([A-Za-z0-9\s'&-]+)/i) ||
+ html.match(/
\s*([A-Za-z0-9\s'&-]+)\s*<\/div>/i);
+ merchant_name = merchantMatch ? merchantMatch[1].trim() : "Uber Eats Merchant";
}
+ // Parse line items (Uber Eats has line_items: [] per Difference 1; Uber Rides parse fare components per Difference 2)
+ const line_items: LineItem[] = [];
+ if (platform === "uber") {
+ // Uber Ride fare components
+ const tripFare = extractTableValue(/Trip fare/i);
+ if (tripFare) line_items.push({ qty: 1, description: "Trip fare", amount: tripFare });
+ const bookingFee = extractTableValue(/Booking Fee/i);
+ if (bookingFee) line_items.push({ qty: 1, description: "Booking Fee", amount: bookingFee });
+ const airportFee = extractTableValue(/Airport fee/i);
+ if (airportFee) line_items.push({ qty: 1, description: "Airport fee", amount: airportFee });
+ } else if (platform === "doordash") {
+ const lineItemMatch = html.match(/(\d+)x\s+([^$]+)\s+\$(\d+\.\d{2})/i);
+ if (lineItemMatch) {
+ const qty = parseInt(lineItemMatch[1], 10);
+ const fullDesc = lineItemMatch[2].trim();
+ const parts = fullDesc.split('•').map(p => p.trim());
+ const description = parts[0];
+ const options = parts.slice(1);
+ const amount = parseFloat(lineItemMatch[3]);
+ line_items.push({ qty, description, amount, options });
+ }
+ }
+
+ // Currency extraction
+ const currencyMatch = html.match(/\b(AUD|NZD|LKR|USD)\b/i);
+ const currency = currencyMatch ? currencyMatch[1].toUpperCase() : "AUD";
+
// Date parsing
const dateMatch = html.match(/Date:\s*(\d{4}-\d{2}-\d{2})/i);
const order_datetime = dateMatch ? `${dateMatch[1]}T12:00:00Z` : "2026-01-15T12:00:00Z";
- // Check if family order
+ // Check if family order (Difference 4)
const is_family = html.includes("[Family]") || html.includes("family");
return {
order_reference: `ORD-${Date.now()}-${Math.floor(Math.random()*1000)}`,
- platform: "doordash",
+ platform,
merchant_name,
order_datetime,
- currency: "AUD",
+ currency,
payment: { credits_amount, card_amount, card_last4 },
totals: {
subtotal,
@@ -161,7 +189,10 @@ export function validateOrderTotals(order: ParsedOrder): boolean {
/**
* Resolves merchant name to category. Never defaults to 'dining' (I4).
*/
-export function resolveMerchantCategory(merchantName: string): { category: string; flagReview: boolean } {
+export function resolveMerchantCategory(merchantName: string, platform?: string): { category: string; flagReview: boolean } {
+ if (platform === "uber" || merchantName.toLowerCase().includes("uber trip")) {
+ return { category: "transport", flagReview: false };
+ }
const lower = merchantName.toLowerCase();
if (lower.includes("woolworths") || lower.includes("aldi") || lower.includes("coles")) {
return { category: "groceries", flagReview: false };