# Google Sheets Multi-Seller Sync Fix

**Date:** 2025-11-20
**Issue:** Only 1 seller's Google Sheet syncing, other 3 sellers' sheets not updating
**Status:** ✅ FIXED

---

## 🐛 The Problem

### Symptoms:
- 4 sellers connected their Gmail accounts to Google Sheets
- Each seller has their own Google Sheet created (headers appear correctly)
- Only 1 seller's sheet receives order updates
- The other 3 sellers' sheets remain empty (no orders sync)

### Root Cause:

**File:** `app/Observers/OrderObserver.php`
**Line:** 557 (before fix)

```php
// OLD CODE (BUGGY):
$seller = $order->store->users()->where('role', 'seller')->first();
```

This line only got the **FIRST** seller assigned to a store, completely ignoring all other sellers!

**Why it happened:**
- When WooCommerce orders come in, the observer needs to determine which seller(s) to sync to
- The original code used `.first()` assuming 1 seller per store
- In production, multiple sellers can be assigned to the same store
- Result: Only the first seller in the database gets synced

---

## ✅ The Fix

### Changed Logic:

**Before:**
- Manual orders → Sync to creator (worked ✓)
- WooCommerce orders → Sync to `.first()` seller only (BUG ❌)

**After:**
- Manual orders → Sync to creator (works ✓)
- WooCommerce orders → Sync to **ALL sellers** assigned to store (FIXED ✓)

### Code Changes:

**File:** `app/Observers/OrderObserver.php`
**Method:** `syncToGoogleSheets()`

```php
// NEW CODE (FIXED):
protected function syncToGoogleSheets(Order $order): void
{
    try {
        $sellersToSync = collect();

        // Case 1: Manual order (created by specific seller)
        if ($order->created_by) {
            $seller = User::find($order->created_by);
            if ($seller) {
                $sellersToSync->push($seller);
            }
        }
        // Case 2: WooCommerce/Webhook order (sync to ALL sellers assigned to store)
        elseif ($order->store) {
            // Get ALL sellers from store (not just first one!)
            $storeSellers = $order->store->users()->where('role', 'seller')->get();
            $sellersToSync = $sellersToSync->merge($storeSellers);
        }

        // Remove duplicates
        $sellersToSync = $sellersToSync->unique('id');

        if ($sellersToSync->isEmpty()) {
            return;
        }

        // Sync to each seller's Google Sheet
        foreach ($sellersToSync as $seller) {
            // Check if seller has Google Sheets sync enabled
            if (!$seller->google_sheets_sync_enabled || !$seller->google_sheet_id) {
                Log::info('Skipping Google Sheets sync - seller not connected', [
                    'order_id' => $order->id,
                    'seller_id' => $seller->id,
                    'seller_name' => $seller->name,
                ]);
                continue;
            }

            // Dispatch sync job to queue
            \App\Jobs\SyncOrderToGoogleSheets::dispatch($seller, $order);

            Log::info('Google Sheets sync job queued', [
                'order_id' => $order->id,
                'seller_id' => $seller->id,
                'seller_name' => $seller->name,
            ]);
        }

    } catch (\Exception $e) {
        Log::error('Failed to queue Google Sheets sync', [
            'order_id' => $order->id,
            'error' => $e->getMessage(),
        ]);
    }
}
```

---

## 🔍 How to Verify the Fix

### 1. Check Logs After Deployment

When a new WooCommerce order comes in, you should see logs like this for **EACH** seller:

```
[2025-11-20 10:30:15] local.INFO: Google Sheets sync job queued {"order_id":233,"seller_id":4,"seller_name":"Seller 1"}
[2025-11-20 10:30:15] local.INFO: Google Sheets sync job queued {"order_id":233,"seller_id":5,"seller_name":"Seller 2"}
[2025-11-20 10:30:15] local.INFO: Google Sheets sync job queued {"order_id":233,"seller_id":6,"seller_name":"Seller 3"}
[2025-11-20 10:30:15] local.INFO: Google Sheets sync job queued {"order_id":233,"seller_id":7,"seller_name":"Seller 4"}
```

Before the fix, you'd only see **1 line** (first seller).

### 2. Manual Sync Test

1. Go to one of the WooCommerce stores
2. Click "Sync Current Month" or "Manual Sync"
3. Check **ALL sellers' Google Sheets** assigned to that store
4. All sheets should now have the same orders

### 3. Check Existing Orders (Backfill)

After deploying the fix, existing orders won't automatically appear in the 3 sellers' sheets. You need to:

**Option A: Trigger update on existing orders**
```bash
# SSH into server
php artisan tinker

# Update all recent orders to trigger observer
Order::where('created_at', '>=', now()->subDays(30))
    ->chunk(100, function($orders) {
        foreach($orders as $order) {
            $order->updated_at = now();
            $order->save(); // Triggers observer
        }
    });
```

**Option B: Manual sync via UI**
1. Each seller clicks "Manual Sync Now" in Google Sheets settings
2. This will sync their last 100 orders

---

## 📊 Impact Assessment

### Who Was Affected:
- **Production servers** with multiple sellers assigned to same WooCommerce store
- **Local development** likely not affected (usually 1 seller per store)

### Data Integrity:
- ✅ No data was lost
- ⚠️ 3 sellers' Google Sheets are missing historical order data
- ✅ Database still has all orders intact
- ✅ First seller's sheet has all data (can be used for reference)

### Fix Timeline:
- **Immediate:** New orders will sync to ALL sellers
- **Manual action needed:** Backfill historical data (see above)

---

## 🚀 Deployment Instructions

1. **Deploy the fix:**
   ```bash
   git pull origin main
   # No migrations needed
   # No cache clear needed
   ```

2. **Verify in logs:**
   ```bash
   tail -f storage/logs/laravel.log | grep "Google Sheets sync job queued"
   ```

3. **Test with new order:**
   - Create a test order in WooCommerce
   - Check logs show sync for ALL sellers
   - Verify all sellers' sheets updated

4. **Backfill historical data (optional):**
   - Use Tinker method above, OR
   - Have each seller click "Manual Sync Now"

---

## 🛡️ Prevention

### Why This Wasn't Caught Earlier:
- Local development typically has 1 seller per store (no issue)
- Unit tests didn't cover multi-seller scenarios
- Integration tests focused on single-seller workflows

### Future Prevention:
1. **Add test case:**
   ```php
   /** @test */
   public function google_sheets_syncs_to_all_sellers_on_store()
   {
       // Create store with 3 sellers
       $store = Store::factory()->create();
       $seller1 = User::factory()->seller()->create(['google_sheets_sync_enabled' => true]);
       $seller2 = User::factory()->seller()->create(['google_sheets_sync_enabled' => true]);
       $seller3 = User::factory()->seller()->create(['google_sheets_sync_enabled' => true]);

       $store->users()->attach([$seller1->id, $seller2->id, $seller3->id]);

       // Create order from store
       $order = Order::factory()->create(['store_id' => $store->id]);

       // Assert sync jobs dispatched for ALL 3 sellers
       Queue::assertPushed(SyncOrderToGoogleSheets::class, 3);
   }
   ```

2. **Documentation:**
   - Update onboarding docs to mention multi-seller sync
   - Add to troubleshooting guide

3. **Monitoring:**
   - Add metric: "Sellers with Google Sheets enabled vs syncing orders"
   - Alert if discrepancy detected

---

## ❓ FAQ

**Q: Will this cause duplicate syncs if a seller is assigned to multiple stores?**
A: No, the code uses `unique('id')` to remove duplicates before syncing.

**Q: What if a seller doesn't have Google Sheets enabled?**
A: The code checks `google_sheets_sync_enabled` and `google_sheet_id` before syncing. They'll be skipped with a log message.

**Q: Will this slow down order creation?**
A: No, syncing is queued via jobs, not synchronous. Order creation speed is unaffected.

**Q: What happens if one seller's token expires?**
A: That seller's sync will fail (logged), but other sellers will still sync successfully. The failed seller needs to reconnect their Google account.

**Q: Can we sync to managers too?**
A: Currently no. The code only syncs to sellers. If you want managers to get copies, they need to be assigned to stores as sellers (with seller role).

---

## 📝 Related Issues

- **Token expiration**: If a seller's sheet stops syncing after this fix, check their Google token hasn't expired
- **Queue not running**: Ensure queue worker is running (`php artisan queue:work` or Horizon)
- **Rate limiting**: Multiple sellers = more API calls. Monitor for rate limit errors (already handled with backoff)

---

**Fix Applied:** 2025-11-20
**Tested:** ✅ Syntax check passed
**Deployed:** Pending production deployment
**Status:** Ready for testing

