import { captureAfterLabel, parseDayMonthYear, parseIdrAmount, } from "../lib/parse-helpers.js"; const QTY_LINE = /^(\d+)\s*x\s*(Rp[\d.,]+)\s*$/i; const RP_ONLY = /^(Rp[\d.,]+)\s*$/i; const URL_LINE = /^(?:https?:\/\/| l.trim()) .filter((l) => l && !isUrlLine(l)); const items = []; let nameParts = []; for (let i = 0; i < lines.length; i++) { const line = lines[i]; const qtyMatch = line.match(QTY_LINE); if (qtyMatch) { const qty = Number(qtyMatch[1]); const unitPrice = parseIdrAmount(qtyMatch[2]); let lineTotal = unitPrice; const next = lines[i + 1]; if (next && RP_ONLY.test(next)) { lineTotal = parseIdrAmount(next); i += 1; } const name = nameParts.join(" ").replace(/\s+/g, " ").trim(); nameParts = []; if (name && unitPrice != null) { items.push({ name, qty, unitPrice, lineTotal: lineTotal ?? unitPrice, }); } continue; } nameParts.push(line); } return items; } function extractItemBlock(body) { const tokoIdx = body.search(/Toko\s*:/i); if (tokoIdx < 0) return null; const afterToko = body.slice(tokoIdx); const shopLineEnd = afterToko.search(/\r?\n/); const rest = shopLineEnd >= 0 ? afterToko.slice(shopLineEnd + 1) : afterToko; const endMatch = rest.search(/Subtotal harga produk|Total belanja/i); return endMatch >= 0 ? rest.slice(0, endMatch) : rest; } function parseTotalBelanja(body) { const m = body.match(/Total\s+belanja\s*\r?\n\s*(Rp[\d.,]+)/i); if (m) return parseIdrAmount(m[1]); // Fallback: value on same line return parseIdrAmount(captureAfterLabel(body, "Total belanja")); } /** * Parse Tokopedia “Pesanan Selesai” body (plain text). * Required: No.Invoice + Total belanja. One row per invoice. */ export function parseTokopediaOrder(body) { if (!body) return null; const invoiceMatch = body.match(/No\.?\s*Invoice\s*:?\s*(\d+)/i); const reference = invoiceMatch?.[1] || null; const amount = parseTotalBelanja(body); if (amount == null || !reference) return null; const cleanRef = reference.trim(); if (!cleanRef) return null; const shopMatch = body.match(/Toko\s*:\s*([^\n<]+)/i); const shop = shopMatch ? shopMatch[1].replace(/[<\s]*https?:\/\/.*$/i, "").trim() || null : null; const items = extractTokopediaItems(extractItemBlock(body)); const tanggalRaw = captureAfterLabel(body, "Tanggal Terima"); const occurredAt = parseDayMonthYear(tanggalRaw); const trackingNumber = captureAfterLabel(body, "Nomor Resi"); const shippingService = captureAfterLabel(body, "Layanan Pengiriman"); const details = {}; if (shop) details.shop = shop; if (items.length) details.items = items; if (trackingNumber && !isUrlLine(trackingNumber)) { details.trackingNumber = trackingNumber.trim(); } if (shippingService && !isUrlLine(shippingService)) { details.shippingService = shippingService.trim(); } return { amount, currency: "IDR", reference: cleanRef, occurredAt, details, }; }