create new menu histori stock audit
This commit is contained in:
@@ -0,0 +1,227 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\WarehouseManagement;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\StockLog;
|
||||
use App\Models\Menu;
|
||||
use App\Models\Dealer;
|
||||
use App\Models\Product;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Yajra\DataTables\DataTables;
|
||||
|
||||
class StockAuditController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$menu = Menu::where('link', 'stock-audit.index')->first();
|
||||
$dealers = Dealer::all();
|
||||
$products = Product::all();
|
||||
|
||||
if ($request->ajax()) {
|
||||
Log::info('Stock audit ajax request received', [
|
||||
'filters' => $request->only(['dealer', 'product', 'change_type', 'date']),
|
||||
'user_id' => auth()->id(),
|
||||
'user_dealer_id' => auth()->user()->dealer_id
|
||||
]);
|
||||
$data = StockLog::query()
|
||||
->with([
|
||||
'stock.product',
|
||||
'stock.dealer',
|
||||
'user.role',
|
||||
'source'
|
||||
])
|
||||
->leftJoin('stocks', 'stock_logs.stock_id', '=', 'stocks.id')
|
||||
->leftJoin('products', 'stocks.product_id', '=', 'products.id')
|
||||
->leftJoin('dealers', 'stocks.dealer_id', '=', 'dealers.id')
|
||||
->leftJoin('users', 'stock_logs.user_id', '=', 'users.id')
|
||||
->select('stock_logs.*');
|
||||
|
||||
// Filter berdasarkan dealer jika user bukan admin
|
||||
if (auth()->user()->dealer_id) {
|
||||
$data->whereHas('stock', function($query) {
|
||||
$query->where('dealer_id', auth()->user()->dealer_id);
|
||||
});
|
||||
}
|
||||
|
||||
// Apply filters from request
|
||||
if ($request->filled('dealer')) {
|
||||
$data->where('dealers.name', 'like', '%' . $request->dealer . '%');
|
||||
}
|
||||
|
||||
if ($request->filled('product')) {
|
||||
$data->where('products.name', 'like', '%' . $request->product . '%');
|
||||
}
|
||||
|
||||
if ($request->filled('change_type')) {
|
||||
$data->where('stock_logs.change_type', $request->change_type);
|
||||
}
|
||||
|
||||
if ($request->filled('date')) {
|
||||
$data->whereDate('stock_logs.created_at', $request->date);
|
||||
}
|
||||
|
||||
return DataTables::of($data)
|
||||
->addIndexColumn()
|
||||
->addColumn('product_name', function($row) {
|
||||
return $row->stock->product->name ?? '-';
|
||||
})
|
||||
->addColumn('dealer_name', function($row) {
|
||||
return $row->stock->dealer->name ?? '-';
|
||||
})
|
||||
->addColumn('change_type', function($row) {
|
||||
$changeType = $row->change_type;
|
||||
$class = match($changeType->value) {
|
||||
'increase' => 'text-success',
|
||||
'decrease' => 'text-danger',
|
||||
'adjustment' => 'text-warning',
|
||||
'no_change' => 'text-muted',
|
||||
default => 'text-dark'
|
||||
};
|
||||
|
||||
return "<span class=\"font-weight-bold {$class}\">{$changeType->label()}</span>";
|
||||
})
|
||||
->addColumn('quantity_change', function($row) {
|
||||
$change = $row->quantity_change;
|
||||
if ($change > 0) {
|
||||
return "<span class=\"text-success\">+{$change}</span>";
|
||||
} elseif ($change < 0) {
|
||||
return "<span class=\"text-danger\">{$change}</span>";
|
||||
} else {
|
||||
return "<span class=\"text-muted\">0</span>";
|
||||
}
|
||||
})
|
||||
->addColumn('stock_before_after', function($row) {
|
||||
return "{$row->previous_quantity} → {$row->new_quantity}";
|
||||
})
|
||||
->addColumn('source_info', function($row) {
|
||||
if ($row->source_type === 'App\\Models\\Mutation') {
|
||||
$mutationNumber = $row->source ? $row->source->mutation_number : '-';
|
||||
return "Mutasi: {$mutationNumber}";
|
||||
} elseif ($row->source_type === 'App\\Models\\Opname') {
|
||||
return "Opname";
|
||||
} else {
|
||||
return $row->source_type ?? '-';
|
||||
}
|
||||
})
|
||||
->addColumn('user_name', function($row) {
|
||||
return $row->user->name ?? '-';
|
||||
})
|
||||
->addColumn('created_at', function($row) {
|
||||
return $row->created_at->format('d M Y, H:i');
|
||||
})
|
||||
->addColumn('action', function($row) {
|
||||
$buttons = '<button type="button" class="btn btn-info btn-sm" onclick="showAuditDetail('.$row->id.')">
|
||||
Detail
|
||||
</button>';
|
||||
return $buttons;
|
||||
})
|
||||
// Filtering
|
||||
->filterColumn('product_name', function($query, $keyword) {
|
||||
$query->where('products.name', 'like', "%{$keyword}%");
|
||||
})
|
||||
->filterColumn('dealer_name', function($query, $keyword) {
|
||||
$query->where('dealers.name', 'like', "%{$keyword}%");
|
||||
})
|
||||
->filterColumn('change_type', function($query, $keyword) {
|
||||
$query->where('stock_logs.change_type', 'like', "%{$keyword}%");
|
||||
})
|
||||
->filterColumn('source_info', function($query, $keyword) {
|
||||
$query->where(function($q) use ($keyword) {
|
||||
$q->where('stock_logs.source_type', 'like', "%{$keyword}%")
|
||||
->orWhere('stock_logs.description', 'like', "%{$keyword}%");
|
||||
});
|
||||
})
|
||||
->filterColumn('user_name', function($query, $keyword) {
|
||||
$query->where('users.name', 'like', "%{$keyword}%");
|
||||
})
|
||||
->filterColumn('created_at', function($query, $keyword) {
|
||||
$query->whereDate('stock_logs.created_at', 'like', "%{$keyword}%");
|
||||
})
|
||||
// Order column mapping
|
||||
->orderColumn('product_name', function($query, $order) {
|
||||
return $query->orderBy('products.name', $order);
|
||||
})
|
||||
->orderColumn('dealer_name', function($query, $order) {
|
||||
return $query->orderBy('dealers.name', $order);
|
||||
})
|
||||
->orderColumn('user_name', function($query, $order) {
|
||||
return $query->orderBy('users.name', $order);
|
||||
})
|
||||
->orderColumn('created_at', function($query, $order) {
|
||||
return $query->orderBy('stock_logs.created_at', $order);
|
||||
})
|
||||
->orderColumn('quantity_change', function($query, $order) {
|
||||
return $query->orderBy('stock_logs.quantity_change', $order);
|
||||
})
|
||||
->orderColumn('stock_before_after', function($query, $order) {
|
||||
return $query->orderBy('stock_logs.previous_quantity', $order);
|
||||
})
|
||||
->orderColumn('change_type', function($query, $order) {
|
||||
return $query->orderBy('stock_logs.change_type', $order);
|
||||
})
|
||||
->orderColumn('source_info', function($query, $order) {
|
||||
return $query->orderBy('stock_logs.source_type', $order);
|
||||
})
|
||||
->rawColumns(['change_type', 'quantity_change', 'action'])
|
||||
->make(true);
|
||||
}
|
||||
|
||||
return view('warehouse_management.stock_audit.index', compact('menu', 'dealers', 'products'));
|
||||
}
|
||||
|
||||
public function getDetail(StockLog $stockLog)
|
||||
{
|
||||
try {
|
||||
$stockLog->load([
|
||||
'stock.product',
|
||||
'stock.dealer',
|
||||
'user.role',
|
||||
'source'
|
||||
]);
|
||||
|
||||
// Format data untuk response
|
||||
$stockLog->created_at_formatted = $stockLog->created_at->format('d M Y, H:i');
|
||||
$stockLog->change_type_label = $stockLog->change_type->label();
|
||||
|
||||
// Detail source berdasarkan tipe
|
||||
$sourceDetail = null;
|
||||
if ($stockLog->source) {
|
||||
if ($stockLog->source_type === 'App\\Models\\Mutation') {
|
||||
$mutation = $stockLog->source;
|
||||
$mutation->load(['fromDealer', 'toDealer', 'requestedBy', 'approvedBy']);
|
||||
|
||||
// Format approved_at date if exists
|
||||
if ($mutation->approved_at) {
|
||||
$mutation->approved_at_formatted = $mutation->approved_at->format('d M Y, H:i');
|
||||
}
|
||||
|
||||
$sourceDetail = [
|
||||
'type' => 'mutation',
|
||||
'data' => $mutation
|
||||
];
|
||||
} elseif ($stockLog->source_type === 'App\\Models\\StockOpname') {
|
||||
$opname = $stockLog->source;
|
||||
$opname->load(['dealer', 'user']);
|
||||
$sourceDetail = [
|
||||
'type' => 'opname',
|
||||
'data' => $opname
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => $stockLog,
|
||||
'source_detail' => $sourceDetail
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Gagal memuat detail audit: ' . $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user