← back to Designer Wallcoverings

DW-Agents/dw-agents/fetch-real-amazon-orders.ts

310 lines

/**
 * Real Amazon Order Fetcher using Puppeteer
 * Logs into Amazon accounts and fetches actual order history
 */

import puppeteer from 'puppeteer';
import * as fs from 'fs';

interface Order {
  id: string;
  item: string;
  vendor: string;
  price: number;
  status: string;
  timestamp: Date;
  orderUrl?: string;
  tracking?: string;
}

interface AmazonAccount {
  email: string;
  password: string;
  type: 'Personal' | 'Business';
}

const PERSONAL_ACCOUNT: AmazonAccount = {
  email: 'nataliaabrams@gmail.com',
  password: 'Urbanon341',
  type: 'Personal'
};

const BUSINESS_ACCOUNT: AmazonAccount = {
  email: 'info@designerwallcoverings.com',
  password: '*Amazonaccess911*',
  type: 'Business'
};

/**
 * Fetch orders from Amazon account using Puppeteer
 */
async function fetchOrdersFromAccount(account: AmazonAccount): Promise<Order[]> {
  const orders: Order[] = [];

  console.log(`\n🔐 Logging into Amazon ${account.type} account: ${account.email}`);

  const browser = await puppeteer.launch({
    headless: true,
    args: [
      '--no-sandbox',
      '--disable-setuid-sandbox',
      '--disable-dev-shm-usage',
      '--disable-accelerated-2d-canvas',
      '--disable-gpu',
      '--window-size=1920x1080'
    ]
  });

  try {
    const page = await browser.newPage();

    // Set user agent to avoid bot detection
    await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36');

    // Set viewport
    await page.setViewport({ width: 1920, height: 1080 });

    console.log('📄 Navigating to Amazon sign-in page...');

    // Go to Amazon sign-in page
    await page.goto('https://www.amazon.com/ap/signin?openid.pape.max_auth_age=0&openid.return_to=https%3A%2F%2Fwww.amazon.com%2F%3Fref_%3Dnav_ya_signin&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.assoc_handle=usflex&openid.mode=checkid_setup&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0', {
      waitUntil: 'networkidle2',
      timeout: 30000
    });

    console.log('✍️  Entering credentials...');

    // Wait for email input
    await page.waitForSelector('#ap_email', { timeout: 10000 });
    await page.type('#ap_email', account.email);
    await page.click('#continue');

    // Wait for password input
    await page.waitForSelector('#ap_password', { timeout: 10000 });
    await page.type('#ap_password', account.password);

    // Click sign in button
    await page.click('#signInSubmit');

    console.log('⏳ Waiting for login to complete...');

    // Wait for navigation after login (or CAPTCHA)
    try {
      await page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 15000 });
    } catch (e) {
      console.log('⚠️  Navigation timeout - checking page state...');
    }

    // Check if we hit a CAPTCHA or 2FA
    const url = page.url();
    if (url.includes('ap/challenge') || url.includes('ap/cvf')) {
      console.log('⚠️  Amazon requires additional verification (CAPTCHA/2FA)');
      console.log('📝 Manual intervention needed. Please:');
      console.log('   1. Run this script in non-headless mode (headless: false)');
      console.log('   2. Complete CAPTCHA/2FA manually');
      console.log('   3. Or save browser cookies for reuse');

      // Take a screenshot for debugging
      await page.screenshot({ path: '/root/Projects/Designer-Wallcoverings/DW-Agents/data/amazon-login-captcha.png' });
      console.log('📸 Screenshot saved: /root/Projects/Designer-Wallcoverings/DW-Agents/data/amazon-login-captcha.png');

      return orders;
    }

    console.log('✅ Login successful! Navigating to order history...');

    // Go to order history page
    await page.goto('https://www.amazon.com/gp/your-account/order-history', {
      waitUntil: 'networkidle2',
      timeout: 30000
    });

    console.log('📦 Parsing order history...');

    // Take screenshot for debugging
    await page.screenshot({ path: `/root/Projects/Designer-Wallcoverings/DW-Agents/data/amazon-orders-${account.type}.png`, fullPage: true });
    console.log(`📸 Screenshot saved: /root/Projects/Designer-Wallcoverings/DW-Agents/data/amazon-orders-${account.type}.png`);

    // Save HTML for debugging
    const html = await page.content();
    fs.writeFileSync(`/root/Projects/Designer-Wallcoverings/DW-Agents/data/amazon-orders-${account.type}.html`, html);
    console.log(`💾 HTML saved: /root/Projects/Designer-Wallcoverings/DW-Agents/data/amazon-orders-${account.type}.html`);

    // Wait for page to load completely
    await page.waitForTimeout(3000);

    // Try multiple selectors for orders
    const hasOrders = await page.evaluate(() => {
      return document.querySelector('.order') !== null ||
             document.querySelector('[data-order-id]') !== null ||
             document.querySelector('.order-card') !== null;
    });

    console.log(`📦 Orders found on page: ${hasOrders}`);

    // Extract order data with multiple fallback selectors
    const orderData = await page.evaluate(() => {
      const orders: any[] = [];

      // Try modern Amazon layout first
      const orderCards = document.querySelectorAll('[data-order-id], .order-card, .order');

      orderCards.forEach((orderEl) => {
        try {
          // Get order ID - try multiple selectors
          let orderId = orderEl.getAttribute('data-order-id') || '';
          if (!orderId) {
            const orderIdEl = orderEl.querySelector('.yohtmlc-order-id span:last-child, .order-info-value, bdi');
            orderId = orderIdEl?.textContent?.trim() || '';
          }

          // Get all text content and look for order ID pattern
          if (!orderId) {
            const text = orderEl.textContent || '';
            const orderMatch = text.match(/\d{3}-\d{7}-\d{7}/);
            if (orderMatch) orderId = orderMatch[0];
          }

          // Get order date
          let orderDateText = '';
          const orderDateEl = orderEl.querySelector('.order-info .a-color-secondary.value, .a-span3 .a-color-secondary, [class*="date"]');
          orderDateText = orderDateEl?.textContent?.trim() || '';

          // Get order total
          let orderTotalText = '';
          const orderTotalEl = orderEl.querySelector('.yohtmlc-order-total .value, .grand-total-price, [class*="total"]');
          orderTotalText = orderTotalEl?.textContent?.trim() || '';

          // Get items in this order - try multiple selectors
          const itemElements = orderEl.querySelectorAll('.a-fixed-left-grid-inner, .shipment-item, [class*="product"], .item-view-left-col-inner');

          if (itemElements.length === 0) {
            // Try getting product titles directly
            const titleEls = orderEl.querySelectorAll('a[class*="title"], .product-title, [class*="product-link"]');
            titleEls.forEach((titleEl) => {
              const itemName = titleEl.textContent?.trim() || '';
              if (itemName && orderId) {
                orders.push({
                  id: orderId,
                  item: itemName,
                  orderDate: orderDateText,
                  total: orderTotalText
                });
              }
            });
          } else {
            itemElements.forEach((itemEl) => {
              const itemNameEl = itemEl.querySelector('.yohtmlc-product-title, .product-title, a[class*="title"]');
              const itemName = itemNameEl?.textContent?.trim() || '';

              if (itemName && orderId) {
                orders.push({
                  id: orderId,
                  item: itemName,
                  orderDate: orderDateText,
                  total: orderTotalText
                });
              }
            });
          }
        } catch (e) {
          console.error('Error parsing order:', e);
        }
      });

      return orders;
    });

    console.log(`✅ Found ${orderData.length} items from orders`);

    // Convert to Order format
    orderData.forEach((data) => {
      try {
        const priceMatch = data.total.match(/[\d.]+/);
        const price = priceMatch ? parseFloat(priceMatch[0]) : 0;

        orders.push({
          id: data.id,
          item: data.item,
          vendor: account.type === 'Business' ? 'Amazon Business' : 'Amazon.com',
          price: price,
          status: 'Delivered',
          timestamp: new Date(data.orderDate || Date.now()),
          orderUrl: `https://www.amazon.com/gp/your-account/order-details?orderID=${data.id}`
        });
      } catch (e) {
        console.error('Error converting order:', e);
      }
    });

  } catch (error) {
    console.error(`❌ Error fetching orders from ${account.type} account:`, error);

    // Take screenshot for debugging
    try {
      const page = (await browser.pages())[0];
      await page.screenshot({ path: `/root/Projects/Designer-Wallcoverings/DW-Agents/data/amazon-error-${account.type}.png` });
      console.log(`📸 Error screenshot saved: /root/Projects/Designer-Wallcoverings/DW-Agents/data/amazon-error-${account.type}.png`);
    } catch (e) {}
  } finally {
    await browser.close();
  }

  return orders;
}

/**
 * Fetch orders from all accounts
 */
async function fetchAllAmazonOrders(): Promise<void> {
  console.log('🚀 Starting Amazon Order Fetcher with Puppeteer\n');
  console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');

  const allOrders: Order[] = [];

  // Fetch from Personal account
  console.log('📱 Fetching Personal Account Orders...');
  const personalOrders = await fetchOrdersFromAccount(PERSONAL_ACCOUNT);
  allOrders.push(...personalOrders);

  console.log(`\n✅ Personal Account: ${personalOrders.length} orders\n`);

  // Wait a bit between accounts to avoid rate limiting
  await new Promise(resolve => setTimeout(resolve, 5000));

  // Fetch from Business account
  console.log('🏢 Fetching Business Account Orders...');
  const businessOrders = await fetchOrdersFromAccount(BUSINESS_ACCOUNT);
  allOrders.push(...businessOrders);

  console.log(`\n✅ Business Account: ${businessOrders.length} orders\n`);

  // Save to file
  const outputPath = '/root/Projects/Designer-Wallcoverings/DW-Agents/data/amazon-orders.json';

  if (allOrders.length > 0) {
    // Sort by date (newest first)
    allOrders.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());

    fs.writeFileSync(outputPath, JSON.stringify(allOrders, null, 2));
    console.log(`\n✅ Saved ${allOrders.length} orders to: ${outputPath}`);

    console.log('\n📊 Sample Orders:');
    allOrders.slice(0, 5).forEach((order, idx) => {
      console.log(`   ${idx + 1}. ${order.item} - $${order.price.toFixed(2)} (${order.vendor})`);
    });
  } else {
    console.log('\n⚠️  No orders fetched. Check screenshots in /root/Projects/Designer-Wallcoverings/DW-Agents/data/ for debugging');
  }

  console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
  console.log('✅ Amazon order fetch complete!');
}

// Run if called directly
if (require.main === module) {
  fetchAllAmazonOrders().catch(console.error);
}

export { fetchAllAmazonOrders, fetchOrdersFromAccount };