瀏覽代碼

feat: add ShopRenter customers cache table and sync functionality #32

- Create shoprenter_customers_cache table with phone number field
- Add indexes for fast lookups (email, phone, customer_id)
- Enable RLS with user-based access control
- Update shoprenter-sync function to sync customers
- Update shoprenter-scheduled-sync to cache customer data
- Customers are now synced with products during manual and scheduled syncs
- Phone numbers are now accessible for calling customers
Claude 5 月之前
父節點
當前提交
c161c0417b

+ 28 - 2
supabase/functions/shoprenter-scheduled-sync/index.ts

@@ -198,7 +198,33 @@ serve(async (req) => {
             const customersData = await fetchCustomers(storeId, page, limit)
 
             if (customersData.items && customersData.items.length > 0) {
-              syncStats.customers.synced += customersData.items.length
+              const customersToCache = customersData.items.map((customer: any) => ({
+                store_id: storeId,
+                shoprenter_customer_id: customer.id,
+                email: customer.email,
+                first_name: customer.firstname,
+                last_name: customer.lastname,
+                phone: customer.phone || null,
+                billing_address: customer.billing_address || null,
+                shipping_address: customer.shipping_address || null,
+                orders_count: customer.orders_count || 0,
+                total_spent: parseFloat(customer.total_spent) || 0,
+                raw_data: customer,
+                last_synced_at: new Date().toISOString()
+              }))
+
+              const { error: upsertError } = await supabaseAdmin
+                .from('shoprenter_customers_cache')
+                .upsert(customersToCache, {
+                  onConflict: 'store_id,shoprenter_customer_id'
+                })
+
+              if (upsertError) {
+                console.error(`[ShopRenter Scheduled Sync] Error caching customers for store ${storeId}:`, upsertError)
+                syncStats.customers.errors += customersToCache.length
+              } else {
+                syncStats.customers.synced += customersToCache.length
+              }
 
               // Check if there are more pages
               if (customersData.pagination && customersData.pagination.total) {
@@ -214,7 +240,7 @@ serve(async (req) => {
             }
           }
 
-          console.log(`[ShopRenter Scheduled Sync] Store ${storeId}: Customers synced: ${syncStats.customers.synced}`)
+          console.log(`[ShopRenter Scheduled Sync] Store ${storeId}: Customers synced: ${syncStats.customers.synced}, errors: ${syncStats.customers.errors}`)
         } catch (error) {
           console.error(`[ShopRenter Scheduled Sync] Customer sync error for store ${storeId}:`, error)
           syncStats.customers.errors++

+ 59 - 0
supabase/functions/shoprenter-sync/index.ts

@@ -133,6 +133,65 @@ serve(async (req) => {
       syncStats.products.errors++
     }
 
+    // Sync Customers
+    try {
+      console.log('[ShopRenter] Syncing customers...')
+      let page = 1
+      let hasMore = true
+      const limit = 50
+
+      while (hasMore) {
+        const customersData = await fetchCustomers(storeId, page, limit)
+
+        if (customersData.items && customersData.items.length > 0) {
+          const customersToCache = customersData.items.map((customer: any) => ({
+            store_id: storeId,
+            shoprenter_customer_id: customer.id,
+            email: customer.email,
+            first_name: customer.firstname,
+            last_name: customer.lastname,
+            phone: customer.phone || null,
+            billing_address: customer.billing_address || null,
+            shipping_address: customer.shipping_address || null,
+            orders_count: customer.orders_count || 0,
+            total_spent: parseFloat(customer.total_spent) || 0,
+            raw_data: customer,
+            last_synced_at: new Date().toISOString()
+          }))
+
+          const { error: upsertError } = await supabaseAdmin
+            .from('shoprenter_customers_cache')
+            .upsert(customersToCache, {
+              onConflict: 'store_id,shoprenter_customer_id'
+            })
+
+          if (upsertError) {
+            console.error('[ShopRenter] Error caching customers:', upsertError)
+            syncStats.customers.errors += customersToCache.length
+          } else {
+            syncStats.customers.synced += customersToCache.length
+          }
+
+          // Check if there are more pages
+          if (customersData.pagination && customersData.pagination.total) {
+            const totalPages = Math.ceil(customersData.pagination.total / limit)
+            hasMore = page < totalPages
+          } else {
+            hasMore = customersData.items.length === limit
+          }
+
+          page++
+        } else {
+          hasMore = false
+        }
+      }
+
+      console.log(`[ShopRenter] Customers synced: ${syncStats.customers.synced}`)
+    } catch (error) {
+      console.error('[ShopRenter] Customer sync error:', error)
+      syncStats.customers.errors++
+    }
+
     // Update store last_sync timestamp
     await supabaseAdmin
       .from('stores')

+ 82 - 0
supabase/migrations/20251031_shoprenter_customers_cache.sql

@@ -0,0 +1,82 @@
+-- Migration: ShopRenter Customers Cache Table
+-- Description: Creates table for caching ShopRenter customer data including phone numbers
+-- Date: 2025-10-31
+-- Related Issue: #32
+
+-- ============================================================================
+-- STEP 1: Create ShopRenter Customers Cache Table
+-- ============================================================================
+
+CREATE TABLE IF NOT EXISTS shoprenter_customers_cache (
+  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+  store_id UUID NOT NULL REFERENCES stores(id) ON DELETE CASCADE,
+  shoprenter_customer_id TEXT NOT NULL,
+  email TEXT NOT NULL,
+  first_name TEXT,
+  last_name TEXT,
+  phone TEXT, -- Critical for calling customers
+  billing_address JSONB,
+  shipping_address JSONB,
+  orders_count INTEGER DEFAULT 0,
+  total_spent DECIMAL(10, 2),
+  raw_data JSONB,
+  last_synced_at TIMESTAMPTZ DEFAULT NOW(),
+  created_at TIMESTAMPTZ DEFAULT NOW(),
+  UNIQUE(store_id, shoprenter_customer_id)
+);
+
+-- ============================================================================
+-- STEP 2: Create Indexes for Fast Lookups
+-- ============================================================================
+
+-- Index for queries by store and last sync time
+CREATE INDEX IF NOT EXISTS idx_shoprenter_customers_store_id
+  ON shoprenter_customers_cache(store_id, last_synced_at DESC);
+
+-- Index for email lookups
+CREATE INDEX IF NOT EXISTS idx_shoprenter_customers_email
+  ON shoprenter_customers_cache(store_id, email);
+
+-- Index for phone number lookups (only non-null values)
+CREATE INDEX IF NOT EXISTS idx_shoprenter_customers_phone
+  ON shoprenter_customers_cache(store_id, phone)
+  WHERE phone IS NOT NULL;
+
+-- Index for customer ID lookups
+CREATE INDEX IF NOT EXISTS idx_shoprenter_customers_customer_id
+  ON shoprenter_customers_cache(store_id, shoprenter_customer_id);
+
+-- ============================================================================
+-- STEP 3: Enable Row Level Security
+-- ============================================================================
+
+ALTER TABLE shoprenter_customers_cache ENABLE ROW LEVEL SECURITY;
+
+-- Policy: Users can view their own customers
+CREATE POLICY "Users can view their shoprenter customers"
+  ON shoprenter_customers_cache FOR SELECT
+  TO authenticated
+  USING (
+    EXISTS (
+      SELECT 1 FROM stores s
+      WHERE s.id = shoprenter_customers_cache.store_id
+      AND s.user_id = auth.uid()
+    )
+  );
+
+-- ============================================================================
+-- Migration Complete
+-- ============================================================================
+
+-- Log migration completion
+DO $$
+BEGIN
+  RAISE NOTICE 'ShopRenter customers cache migration completed successfully';
+  RAISE NOTICE 'Created tables:';
+  RAISE NOTICE '  - shoprenter_customers_cache (Customer data with phone numbers)';
+  RAISE NOTICE '';
+  RAISE NOTICE 'Next steps:';
+  RAISE NOTICE '1. Update shoprenter-sync Edge Function to sync customers';
+  RAISE NOTICE '2. Update shoprenter-scheduled-sync Edge Function to include customers';
+  RAISE NOTICE '3. Test customer sync with existing ShopRenter stores';
+END $$;