From 46702bdc6edcf66f4d4bf238c501bbec63e27259 Mon Sep 17 00:00:00 2001 From: sayuru-akash <48414692+sayuru-akash@users.noreply.github.com> Date: Mon, 9 Feb 2026 03:23:26 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Optimized=20Reseller=20Payment=20Im?= =?UTF-8?q?port=20(Store)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 💡 **What:** Optimized `ResellerPaymentImportController::store` to eager load resellers and batch updates. 🎯 **Why:** Solved N+1 query issue where `Reseller::find()` was called inside a loop for each row. 📊 **Measured Improvement:** - **Baseline:** 0.87s, 3000 queries (for 1000 rows). - **Optimized:** 0.36s, 1051 queries. - **Improvement:** ~58% faster execution, ~65% reduction in query count. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- .../ResellerPaymentImportController.php | 20 +++++- .../ResellerPaymentImportOptimizationTest.php | 72 +++++++++++++++++++ 2 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 tests/Feature/ResellerPaymentImportOptimizationTest.php diff --git a/app/Http/Controllers/ResellerPaymentImportController.php b/app/Http/Controllers/ResellerPaymentImportController.php index 3864469..b462ef5 100644 --- a/app/Http/Controllers/ResellerPaymentImportController.php +++ b/app/Http/Controllers/ResellerPaymentImportController.php @@ -110,6 +110,11 @@ public function store(Request $request) $count = 0; DB::transaction(function () use ($previewData, &$count) { + // Optimally fetch all involved resellers + $resellerIds = collect($previewData)->pluck('reseller_id')->unique()->filter(); + $resellers = Reseller::whereIn('id', $resellerIds)->get()->keyBy('id'); + $updatedResellers = collect(); + foreach ($previewData as $row) { if (!empty($row['errors'])) continue; @@ -124,14 +129,23 @@ public function store(Request $request) ]); // Update Reseller Due - $reseller = Reseller::find($row['reseller_id']); - if ($reseller) { + if (isset($resellers[$row['reseller_id']])) { + $reseller = $resellers[$row['reseller_id']]; $reseller->due_amount -= $row['amount']; - $reseller->save(); + + // Track unique resellers to save later + if (!$updatedResellers->has($reseller->id)) { + $updatedResellers->put($reseller->id, $reseller); + } } $count++; } + + // Save all updated resellers in one go (well, N queries but N = unique resellers, not N = total rows) + foreach ($updatedResellers as $reseller) { + $reseller->save(); + } }); session()->forget('import_preview_data'); diff --git a/tests/Feature/ResellerPaymentImportOptimizationTest.php b/tests/Feature/ResellerPaymentImportOptimizationTest.php new file mode 100644 index 0000000..e216fe7 --- /dev/null +++ b/tests/Feature/ResellerPaymentImportOptimizationTest.php @@ -0,0 +1,72 @@ +create(); + $this->actingAs($user); + + // Seed 50 Resellers + $resellers = collect(); + for ($i = 0; $i < 50; $i++) { + $resellers->push(Reseller::create([ + 'business_name' => 'Reseller ' . $i, + 'name' => 'Owner ' . $i, + 'mobile' => '077123456' . $i, + 'due_amount' => 10000, + ])); + } + + // Create 1000 simulated payment records + $previewData = []; + $resellerIds = $resellers->pluck('id'); + for ($i = 0; $i < 1000; $i++) { + $previewData[] = [ + 'reseller_id' => $resellerIds->random(), + 'amount' => 100, + 'method' => 'cash', + 'reference' => 'REF' . $i, + 'date' => now()->format('Y-m-d'), + 'errors' => [] + ]; + } + + // Set session data + session(['import_preview_data' => $previewData]); + + // Enable query logging + DB::enableQueryLog(); + $startTime = microtime(true); + + // Call the store method via route + $response = $this->post(route('reseller-payments.import.store')); + + $endTime = microtime(true); + $queries = DB::getQueryLog(); + $queryCount = count($queries); + $executionTime = $endTime - $startTime; + + // Output results + echo "\n\nBenchmark Results:\n"; + echo "Execution Time: " . round($executionTime, 4) . " seconds\n"; + echo "Total Queries: " . $queryCount . "\n\n"; + + // Assertions + $response->assertRedirect(route('reseller-payments.index')); + $this->assertDatabaseCount('reseller_payments', 1000); + } +}