fix feature report stock product
This commit is contained in:
178
app/Services/StockReportService.php
Normal file
178
app/Services/StockReportService.php
Normal file
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Product;
|
||||
use App\Models\Dealer;
|
||||
use App\Models\Stock;
|
||||
use App\Models\StockLog;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class StockReportService
|
||||
{
|
||||
/**
|
||||
* Get stock report data for all products and dealers on a specific date
|
||||
*/
|
||||
public function getStockReportData($targetDate = null)
|
||||
{
|
||||
$targetDate = $targetDate ? Carbon::parse($targetDate) : now();
|
||||
|
||||
// Get all dealers
|
||||
$dealers = Dealer::orderBy('name')->get();
|
||||
|
||||
// Get all active products
|
||||
$products = Product::where('active', true)
|
||||
->with(['category'])
|
||||
->orderBy('name')
|
||||
->get();
|
||||
|
||||
$data = [];
|
||||
|
||||
foreach ($products as $product) {
|
||||
$row = [
|
||||
'product_id' => $product->id,
|
||||
'product_code' => $product->code,
|
||||
'product_name' => $product->name,
|
||||
'category_name' => $product->category ? $product->category->name : '-',
|
||||
'unit' => $product->unit ?? '-',
|
||||
'total_stock' => 0
|
||||
];
|
||||
|
||||
// Calculate stock for each dealer on the target date
|
||||
foreach ($dealers as $dealer) {
|
||||
$stockOnDate = $this->getStockOnDate($product->id, $dealer->id, $targetDate);
|
||||
$row["dealer_{$dealer->id}"] = $stockOnDate;
|
||||
$row['total_stock'] += $stockOnDate;
|
||||
}
|
||||
|
||||
$data[] = $row;
|
||||
}
|
||||
|
||||
return [
|
||||
'data' => $data,
|
||||
'dealers' => $dealers
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get stock quantity for a specific product and dealer on a given date
|
||||
*/
|
||||
public function getStockOnDate($productId, $dealerId, $targetDate)
|
||||
{
|
||||
// Get the latest stock log entry before or on the target date
|
||||
$latestStockLog = StockLog::whereHas('stock', function($query) use ($productId, $dealerId) {
|
||||
$query->where('product_id', $productId)
|
||||
->where('dealer_id', $dealerId);
|
||||
})
|
||||
->where('created_at', '<=', $targetDate->endOfDay())
|
||||
->orderBy('created_at', 'desc')
|
||||
->first();
|
||||
|
||||
if ($latestStockLog) {
|
||||
// Return the new_quantity from the latest log entry
|
||||
return $latestStockLog->new_quantity;
|
||||
}
|
||||
|
||||
// If no stock log found, check if there's a current stock record
|
||||
$currentStock = Stock::where('product_id', $productId)
|
||||
->where('dealer_id', $dealerId)
|
||||
->first();
|
||||
|
||||
if ($currentStock) {
|
||||
// Check if the stock was created before or on the target date
|
||||
if ($currentStock->created_at <= $targetDate) {
|
||||
return $currentStock->quantity;
|
||||
}
|
||||
}
|
||||
|
||||
// No stock data available for this date
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get optimized stock data using a single query approach
|
||||
*/
|
||||
public function getOptimizedStockReportData($targetDate = null)
|
||||
{
|
||||
$targetDate = $targetDate ? Carbon::parse($targetDate) : now();
|
||||
|
||||
// Get all dealers
|
||||
$dealers = Dealer::orderBy('name')->get();
|
||||
|
||||
// Get all active products with their stock data
|
||||
$products = Product::where('active', true)
|
||||
->with(['category', 'stocks.dealer'])
|
||||
->orderBy('name')
|
||||
->get();
|
||||
|
||||
$data = [];
|
||||
|
||||
foreach ($products as $product) {
|
||||
$row = [
|
||||
'product_id' => $product->id,
|
||||
'product_code' => $product->code,
|
||||
'product_name' => $product->name,
|
||||
'category_name' => $product->category ? $product->category->name : '-',
|
||||
'unit' => $product->unit ?? '-',
|
||||
'total_stock' => 0
|
||||
];
|
||||
|
||||
// Calculate stock for each dealer on the target date
|
||||
foreach ($dealers as $dealer) {
|
||||
$stockOnDate = $this->getOptimizedStockOnDate($product->id, $dealer->id, $targetDate);
|
||||
$row["dealer_{$dealer->id}"] = $stockOnDate;
|
||||
$row['total_stock'] += $stockOnDate;
|
||||
}
|
||||
|
||||
$data[] = $row;
|
||||
}
|
||||
|
||||
return [
|
||||
'data' => $data,
|
||||
'dealers' => $dealers
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimized method to get stock on date using subquery
|
||||
*/
|
||||
private function getOptimizedStockOnDate($productId, $dealerId, $targetDate)
|
||||
{
|
||||
try {
|
||||
// Use a subquery to get the latest stock log entry efficiently
|
||||
$latestStockLog = DB::table('stock_logs')
|
||||
->join('stocks', 'stock_logs.stock_id', '=', 'stocks.id')
|
||||
->where('stocks.product_id', $productId)
|
||||
->where('stocks.dealer_id', $dealerId)
|
||||
->where('stock_logs.created_at', '<=', $targetDate->endOfDay())
|
||||
->orderBy('stock_logs.created_at', 'desc')
|
||||
->select('stock_logs.new_quantity')
|
||||
->first();
|
||||
|
||||
if ($latestStockLog) {
|
||||
return $latestStockLog->new_quantity;
|
||||
}
|
||||
|
||||
// If no stock log found, check current stock
|
||||
$currentStock = Stock::where('product_id', $productId)
|
||||
->where('dealer_id', $dealerId)
|
||||
->first();
|
||||
|
||||
if ($currentStock && $currentStock->created_at <= $targetDate) {
|
||||
return $currentStock->quantity;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} catch (\Exception $e) {
|
||||
// Log error and return 0
|
||||
Log::error('Error getting stock on date: ' . $e->getMessage(), [
|
||||
'product_id' => $productId,
|
||||
'dealer_id' => $dealerId,
|
||||
'target_date' => $targetDate
|
||||
]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user