query('filter', 'bulan'); $page = $request->query('page', 1); $allSalesNames = Transaksi::select('nama_sales')->distinct()->pluck('nama_sales'); if ($filter === 'hari') { return $this->laporanHarian($page, $allSalesNames); } return $this->laporanBulanan($page, $allSalesNames); } private function laporanHarian(int $page, Collection $allSalesNames) { $perPage = 7; $endDate = Carbon::today()->subDays(($page - 1) * $perPage); $startDate = $endDate->copy()->subDays($perPage - 1); $transaksis = Transaksi::with('itemTransaksi.item.produk') ->whereBetween('created_at', [$startDate->startOfDay(), $endDate->endOfDay()]) ->orderBy('created_at', 'desc') ->get(); $transaksisByDay = $transaksis->groupBy(function ($transaksi) { return Carbon::parse($transaksi->created_at)->format('Y-m-d'); }); $period = CarbonPeriod::create($startDate, $endDate); $laporan = []; foreach ($period as $date) { $dateString = $date->format('Y-m-d'); $tanggalFormatted = $date->isoFormat('dddd, D MMMM Y'); if (isset($transaksisByDay[$dateString])) { $transaksisPerTanggal = $transaksisByDay[$dateString]; $salesDataTransaksi = $transaksisPerTanggal->groupBy('nama_sales') ->map(fn($transaksisPerSales) => $this->hitungDataSales($transaksisPerSales)); $fullSalesData = $allSalesNames->map(function ($namaSales) use ($salesDataTransaksi) { return $salesDataTransaksi->get($namaSales) ?? $this->defaultSalesData($namaSales); }); $totalItem = $fullSalesData->sum('item_terjual'); $totalBerat = $fullSalesData->sum('berat_terjual_raw'); $totalPendapatan = $fullSalesData->sum('pendapatan_raw'); $laporan[$dateString] = [ 'tanggal' => $tanggalFormatted, 'total_item_terjual' => $totalItem > 0 ? $totalItem : '-', 'total_berat' => $totalBerat > 0 ? number_format($totalBerat, 2, ',', '.') . 'g' : '-', 'total_pendapatan' => $totalPendapatan > 0 ? 'Rp' . number_format($totalPendapatan, 2, ',', '.') : '-', 'sales' => $this->formatSalesDataValues($fullSalesData)->values(), ]; } else { $laporan[$dateString] = [ 'tanggal' => $tanggalFormatted, 'total_item_terjual' => '-', 'total_berat' => '-', 'total_pendapatan' => '-', 'sales' => [], ]; } } $totalHariUntukPaginasi = 365; $paginatedData = new LengthAwarePaginator( array_reverse(array_values($laporan)), $totalHariUntukPaginasi, $perPage, $page, ['path' => request()->url(), 'query' => request()->query()] ); return response()->json($paginatedData); } private function laporanBulanan(int $page, Collection $allSalesNames) { $perPage = 12; $transaksis = Transaksi::with('itemTransaksi.item.produk') ->orderBy('created_at', 'desc') ->get(); $laporan = $transaksis->groupBy(function ($transaksi) { return Carbon::parse($transaksi->created_at)->format('F Y'); }) ->map(function ($transaksisPerTanggal, $tanggal) use ($allSalesNames) { $salesDataTransaksi = $transaksisPerTanggal ->groupBy('nama_sales') ->map(fn($transaksisPerSales) => $this->hitungDataSales($transaksisPerSales)); $fullSalesData = $allSalesNames->map(function ($namaSales) use ($salesDataTransaksi) { return $salesDataTransaksi->get($namaSales) ?? $this->defaultSalesData($namaSales); }); $totalItem = $fullSalesData->sum('item_terjual'); $totalBerat = $fullSalesData->sum('berat_terjual_raw'); $totalPendapatan = $fullSalesData->sum('pendapatan_raw'); return [ 'tanggal' => $tanggal, 'total_item_terjual' => $totalItem > 0 ? $totalItem : '-', 'total_berat' => $totalBerat > 0 ? number_format($totalBerat, 2, ',', '.') . 'g' : '-', 'total_pendapatan' => $totalPendapatan > 0 ? 'Rp' . number_format($totalPendapatan, 2, ',', '.') : '-', 'sales' => $this->formatSalesDataValues($fullSalesData)->values(), ]; }); $paginatedData = new LengthAwarePaginator( $laporan->forPage($page, $perPage)->values(), $laporan->count(), $perPage, $page, ['path' => request()->url(), 'query' => request()->query()] ); return response()->json($paginatedData); } private function hitungDataSales(Collection $transaksisPerSales): array { $itemTerjual = $transaksisPerSales->sum(fn($t) => $t->itemTransaksi->count()); $beratTerjual = $transaksisPerSales->sum( fn($t) => $t->itemTransaksi->sum(fn($it) => $it->item->produk->berat ?? 0) ); $pendapatan = $transaksisPerSales->sum('total_harga'); return [ 'nama' => $transaksisPerSales->first()->nama_sales, 'item_terjual' => $itemTerjual, 'berat_terjual_raw' => $beratTerjual, 'pendapatan_raw' => $pendapatan, ]; } private function defaultSalesData(string $namaSales): array { return [ 'nama' => $namaSales, 'item_terjual' => 0, 'berat_terjual_raw' => 0, 'pendapatan_raw' => 0, ]; } private function formatSalesDataValues(Collection $salesData): Collection { return $salesData->map(function ($sale) { $sale['item_terjual'] = $sale['item_terjual'] > 0 ? $sale['item_terjual'] : '-'; $sale['berat_terjual'] = $sale['berat_terjual_raw'] > 0 ? number_format($sale['berat_terjual_raw'], 2, ',', '.') . 'g' : '-'; $sale['pendapatan'] = $sale['pendapatan_raw'] > 0 ? 'Rp' . number_format($sale['pendapatan_raw'], 2, ',', '.') : '-'; unset($sale['berat_terjual_raw'], $sale['pendapatan_raw']); return $sale; }); } public function detail(Request $request) { // 1. VALIDASI DAN PENGAMBILAN PARAMETER FILTER $request->validate([ 'tanggal' => 'required|date_format:Y-m-d', ]); $tanggal = $request->query('tanggal'); $namaSales = $request->query('nama_sales'); $posisi = $request->query('posisi'); $namaPembeli = $request->query('nama_pembeli'); // Untuk pencarian $carbonDate = Carbon::parse($tanggal); // 2. QUERY UTAMA UNTUK MENGAMBIL DATA PRODUK YANG TERJUAL BERDASARKAN FILTER // Query ini hanya akan mengambil produk yang memiliki transaksi sesuai filter. $produkTerjualQuery = ItemTransaksi::query() ->join('items', 'item_transaksis.id_item', '=', 'items.id') ->join('produks', 'items.id_produk', '=', 'produks.id') ->join('transaksis', 'item_transaksis.id_transaksi', '=', 'transaksis.id') // Filter Wajib: Tanggal ->whereDate('transaksis.created_at', $carbonDate) // Filter Opsional: Nama Sales ->when($namaSales, function ($query, $namaSales) { return $query->where('transaksis.nama_sales', $namaSales); }) // Filter Opsional: Posisi Asal Item ->when($posisi, function ($query, $posisi) { return $query->where('item_transaksis.posisi_asal', $posisi); }) // Filter Opsional: Nama Pembeli (menggunakan LIKE untuk pencarian) ->when($namaPembeli, function ($query, $namaPembeli) { return $query->where('transaksis.nama_pembeli', 'like', "%{$namaPembeli}%"); }) ->select( 'produks.id as id_produk', 'produks.nama as nama_produk', DB::raw('COUNT(item_transaksis.id) as jumlah_item_terjual'), DB::raw('SUM(produks.berat) as berat_terjual'), DB::raw('SUM(item_transaksis.harga_deal) as pendapatan') ) ->groupBy('produks.id', 'produks.nama') ->get() // Mengubah collection menjadi array asosiatif dengan key id_produk agar mudah dicari ->keyBy('id_produk'); // 3. MENGAMBIL SEMUA PRODUK DARI DATABASE $semuaProduk = Produk::query()->select('id', 'nama')->get(); // 4. MENGGABUNGKAN DATA SEMUA PRODUK DENGAN PRODUK YANG TERJUAL $detailItem = $semuaProduk->map(function ($produk) use ($produkTerjualQuery) { // Cek apakah produk ini ada di dalam daftar produk yang terjual if ($produkTerjualQuery->has($produk->id)) { $dataTerjual = $produkTerjualQuery->get($produk->id); return [ 'nama_produk' => $produk->nama, 'jumlah_item_terjual' => (int) $dataTerjual->jumlah_item_terjual, 'berat_terjual' => (float) $dataTerjual->berat_terjual, 'pendapatan' => (float) $dataTerjual->pendapatan, ]; } else { // Jika produk tidak terjual, berikan nilai default "-" return [ 'nama_produk' => $produk->nama, 'jumlah_item_terjual' => '-', 'berat_terjual' => '-', 'pendapatan' => '-', ]; } }); // 5. MENGHITUNG TOTAL REKAP HARIAN DARI DATA YANG SUDAH DIFILTER $totalPendapatan = $produkTerjualQuery->sum('pendapatan'); $totalItemTerjual = $produkTerjualQuery->sum('jumlah_item_terjual'); $totalBeratTerjual = $produkTerjualQuery->sum('berat_terjual'); // 6. MENYUSUN STRUKTUR RESPONSE FINAL $response = [ 'filter' => [ 'tanggal' => $carbonDate->isoFormat('dddd, D MMMM Y'), 'nama_sales' => $namaSales, 'posisi' => $posisi, 'nama_pembeli' => $namaPembeli, ], 'rekap_harian' => [ 'total_item_terjual' => $totalItemTerjual, 'total_berat_terjual' => $totalBeratTerjual, 'total_pendapatan' => $totalPendapatan, ], 'produk' => $detailItem, ]; return response()->json($response); } }