Compare commits

..

No commits in common. "f01b2ba34aeda6836b9d96cd7f5aa5c86da45372" and "982b14e46a9a314fd84dd347b54ef7855a78d327" have entirely different histories.

View File

@ -54,9 +54,9 @@ class LaporanService
} }
/** /**
* Get sales detail aggregated by product (NO PAGINATION - all data). * Get paginated sales detail aggregated by product.
* *
* @param array $params Filter parameters (tanggal, sales_id, nampan_id, nama_pembeli) * @param array $params Filter parameters (tanggal, sales_id, nampan_id, nama_pembeli, page, per_page)
* @return array Report data structure * @return array Report data structure
* @throws \Exception * @throws \Exception
*/ */
@ -65,17 +65,16 @@ class LaporanService
$startDate = Carbon::parse($params['start_date'])->startOfDay(); $startDate = Carbon::parse($params['start_date'])->startOfDay();
$endDate = Carbon::parse($params['end_date'])->endOfDay(); $endDate = Carbon::parse($params['end_date'])->endOfDay();
// TAMBAH: Validasi range max 30 hari // TAMBAH: Validasi range max 30 hari (backup request)
if ($startDate->diffInDays($endDate) > 30) { if ($startDate->diffInDays($endDate) > 30) {
throw new \InvalidArgumentException('Interval tanggal maksimal 30 hari.'); throw new \InvalidArgumentException('Interval tanggal maksimal 30 hari.');
} }
// FIXED: Skip pagination params untuk data utama
$page = $params['page'] ?? 1; $page = $params['page'] ?? 1;
$perPage = $params['per_page'] ?? self::DEFAULT_PER_PAGE; $perPage = $params['per_page'] ?? self::DEFAULT_PER_PAGE;
// --- Step 1: Totals --- // --- Step 1: Totals ---
$totalsQuery = $this->buildBaseItemQueryForRange($startDate, $endDate); $totalsQuery = $this->buildBaseItemQueryForRange($startDate, $endDate); // FIXED: Call benar
$this->applyFilters($totalsQuery, $params); $this->applyFilters($totalsQuery, $params);
$totalsResult = $totalsQuery->select( $totalsResult = $totalsQuery->select(
@ -90,7 +89,7 @@ class LaporanService
'total_pendapatan' => $this->helper->formatCurrency($totalsResult->total_pendapatan), 'total_pendapatan' => $this->helper->formatCurrency($totalsResult->total_pendapatan),
]; ];
// --- Step 2: Subquery for all products --- // --- Step 2: Subquery ---
$salesSubQuery = $this->buildBaseItemQueryForRange($startDate, $endDate) $salesSubQuery = $this->buildBaseItemQueryForRange($startDate, $endDate)
->select( ->select(
'produks.id as id_produk', 'produks.id as id_produk',
@ -102,8 +101,8 @@ class LaporanService
$this->applyFilters($salesSubQuery, $params); $this->applyFilters($salesSubQuery, $params);
// --- Step 3: All products (NO PAGINATION) --- // --- Step 3: Paginated products ---
$semuaProduk = Produk::select( $semuaProdukPaginated = Produk::select(
'produks.id', 'produks.id',
'produks.nama as nama_produk', 'produks.nama as nama_produk',
'sales_data.jumlah_item_terjual', 'sales_data.jumlah_item_terjual',
@ -114,10 +113,10 @@ class LaporanService
$join->on('produks.id', '=', 'sales_data.id_produk'); $join->on('produks.id', '=', 'sales_data.id_produk');
}) })
->orderBy('produks.nama') ->orderBy('produks.nama')
->get(); // FIXED: get() instead of paginate() ->paginate($perPage, ['*'], 'page', $page);
// --- Step 4: Map & filter --- // --- Step 4: Map & filter ---
$detailItem = $semuaProduk->map(function ($item) { $detailItem = $semuaProdukPaginated->map(function ($item) {
return [ return [
'nama_produk' => $item->nama_produk, 'nama_produk' => $item->nama_produk,
'jumlah_item_terjual' => $item->jumlah_item_terjual ? (int) $item->jumlah_item_terjual : 0, 'jumlah_item_terjual' => $item->jumlah_item_terjual ? (int) $item->jumlah_item_terjual : 0,
@ -128,8 +127,13 @@ class LaporanService
return $item['jumlah_item_terjual'] > 0; return $item['jumlah_item_terjual'] > 0;
}); });
// FIXED: Simple collection without pagination $paginatedFiltered = new \Illuminate\Pagination\LengthAwarePaginator(
$filteredCollection = $detailItem->values(); $detailItem->forPage($page, $perPage),
$detailItem->count(), // FIXED: Total dari filtered
$perPage,
$page,
['path' => request()->url(), 'query' => request()->query()]
);
// --- Step 5: Response --- // --- Step 5: Response ---
$filterInfo = $this->helper->buildProdukFilterInfo($startDate, $endDate, $params); $filterInfo = $this->helper->buildProdukFilterInfo($startDate, $endDate, $params);
@ -137,16 +141,8 @@ class LaporanService
return [ return [
'filter' => $filterInfo, 'filter' => $filterInfo,
'rekap_interval' => $rekapInterval, 'rekap_interval' => $rekapInterval,
'produk' => $filteredCollection, 'produk' => $paginatedFiltered->getCollection(),
'pagination' => [ 'pagination' => $this->helper->buildPaginationInfo($paginatedFiltered), // FIXED: Dari filtered
'current_page' => 1,
'from' => 1,
'last_page' => 1,
'per_page' => $filteredCollection->count(),
'to' => $filteredCollection->count(),
'total' => $filteredCollection->count(),
'has_more_pages' => false,
],
]; ];
} }
@ -158,13 +154,6 @@ class LaporanService
->whereBetween('transaksis.created_at', [$startDate, $endDate]); ->whereBetween('transaksis.created_at', [$startDate, $endDate]);
} }
/**
* Get sales detail aggregated by nampan (NO PAGINATION - all data).
*
* @param array $params Filter parameters (tanggal, sales_id, produk_id, nama_pembeli)
* @return array Report data structure
* @throws \Exception
*/
public function getDetailPerNampan(array $params) public function getDetailPerNampan(array $params)
{ {
$startDate = Carbon::parse($params['start_date'])->startOfDay(); $startDate = Carbon::parse($params['start_date'])->startOfDay();
@ -177,7 +166,7 @@ class LaporanService
$page = $params['page'] ?? 1; $page = $params['page'] ?? 1;
$perPage = $params['per_page'] ?? self::DEFAULT_PER_PAGE; $perPage = $params['per_page'] ?? self::DEFAULT_PER_PAGE;
$nampanTerjualQuery = $this->buildBaseItemQueryForRange($startDate, $endDate); $nampanTerjualQuery = $this->buildBaseItemQueryForRange($startDate, $endDate); // FIXED: Range
$this->applyNampanFilters($nampanTerjualQuery, $params); $this->applyNampanFilters($nampanTerjualQuery, $params);
$nampanTerjual = $nampanTerjualQuery $nampanTerjual = $nampanTerjualQuery
@ -201,31 +190,27 @@ class LaporanService
}); });
$totals = $this->helper->calculateTotals($nampanTerjualRaw); $totals = $this->helper->calculateTotals($nampanTerjualRaw);
// FIXED: Get all nampan without pagination $semuaNampanPaginated = $this->helper->getAllNampanWithPagination($page, $perPage);
$semuaNampan = $this->helper->getAllNampanWithPagination(1, PHP_INT_MAX); // Skip pagination $detailItem = $this->helper->mapNampanWithSalesData($semuaNampanPaginated, $nampanTerjual)
$detailItem = $this->helper->mapNampanWithSalesData($semuaNampan, $nampanTerjual)
->filter(function ($item) { ->filter(function ($item) {
return $item['jumlah_item_terjual'] > 0; return $item['jumlah_item_terjual'] > 0; // FIXED: Int compare, no DEFAULT_DISPLAY check
}); });
// FIXED: Simple collection without pagination $paginatedFiltered = new \Illuminate\Pagination\LengthAwarePaginator(
$filteredCollection = $detailItem->values(); $detailItem->forPage($page, $perPage),
$detailItem->count(),
$perPage,
$page,
['path' => request()->url(), 'query' => request()->query()]
);
$filterInfo = $this->helper->buildNampanFilterInfo($startDate, $endDate, $params); $filterInfo = $this->helper->buildNampanFilterInfo($startDate, $endDate, $params); // FIXED: Range helper
return [ return [
'filter' => $filterInfo, 'filter' => $filterInfo,
'rekap_interval' => $totals, 'rekap_interval' => $totals, // FIXED: Rename
'nampan' => $filteredCollection, 'nampan' => $paginatedFiltered->getCollection(),
'pagination' => [ 'pagination' => $this->helper->buildPaginationInfo($paginatedFiltered),
'current_page' => 1,
'from' => 1,
'last_page' => 1,
'per_page' => $filteredCollection->count(),
'to' => $filteredCollection->count(),
'total' => $filteredCollection->count(),
'has_more_pages' => false,
],
]; ];
} }
@ -269,14 +254,14 @@ class LaporanService
$startDate = Carbon::parse($params['start_date'])->format('Ymd'); $startDate = Carbon::parse($params['start_date'])->format('Ymd');
$endDate = Carbon::parse($params['end_date'])->format('Ymd'); $endDate = Carbon::parse($params['end_date'])->format('Ymd');
$fileName = "laporan_per_produk_{$startDate}_to_{$endDate}.{$format}"; $fileName = "laporan_per_produk_{$startDate}_to_{$endDate}.{$format}"; // FIXED: Range filename
if ($format === 'pdf') { if ($format === 'pdf') {
$pdf = PDF::loadView('exports.perproduk_pdf', [ $pdf = PDF::loadView('exports.perproduk_pdf', [
'data' => $data, 'data' => $data,
'title' => 'Laporan Detail Per Produk' 'title' => 'Laporan Detail Per Produk'
]); ]);
$pdf->setPaper('a4', 'portrait'); $pdf->setPaper('a4', 'portrait'); // FIXED: Typo 'potrait'
return $pdf->download($fileName); return $pdf->download($fileName);
} }
@ -293,7 +278,7 @@ class LaporanService
$startDate = Carbon::parse($params['start_date'])->format('Ymd'); $startDate = Carbon::parse($params['start_date'])->format('Ymd');
$endDate = Carbon::parse($params['end_date'])->format('Ymd'); $endDate = Carbon::parse($params['end_date'])->format('Ymd');
$fileName = "laporan_per_nampan_{$startDate}_to_{$endDate}.{$format}"; $fileName = "laporan_per_nampan_{$startDate}_to_{$endDate}.{$format}"; // FIXED: Range
if ($format === 'pdf') { if ($format === 'pdf') {
$pdf = PDF::loadView('exports.pernampan_pdf', [ $pdf = PDF::loadView('exports.pernampan_pdf', [
@ -349,14 +334,14 @@ class LaporanService
'pendapatan' => $this->helper->formatCurrency($dataTerjual->pendapatan), 'pendapatan' => $this->helper->formatCurrency($dataTerjual->pendapatan),
]; ];
} }
return null; return null; // Akan difilter
})->filter(); })->filter(); // FIXED: Filter null/kosong
$filterInfo = $this->helper->buildProdukFilterInfo($startDate, $endDate, $params); $filterInfo = $this->helper->buildProdukFilterInfo($startDate, $endDate, $params);
return [ return [
'filter' => $filterInfo, 'filter' => $filterInfo,
'rekap_interval' => $totals, 'rekap_interval' => $totals, // FIXED: Rename
'produk' => $detailItem->values(), 'produk' => $detailItem->values(),
]; ];
} }
@ -391,7 +376,7 @@ class LaporanService
$totals = $this->helper->calculateTotals($nampanTerjualRaw); $totals = $this->helper->calculateTotals($nampanTerjualRaw);
$semuaPosisi = DB::table('item_transaksis') $semuaPosisi = DB::table('item_transaksis')
->whereBetween('created_at', [$startDate, $endDate]) ->whereBetween('created_at', [$startDate, $endDate]) // FIXED: Filter posisi di range
->select('posisi_asal') ->select('posisi_asal')
->distinct() ->distinct()
->pluck('posisi_asal') ->pluck('posisi_asal')
@ -408,10 +393,10 @@ class LaporanService
'pendapatan' => $this->helper->formatCurrency($dataTerjual->pendapatan), 'pendapatan' => $this->helper->formatCurrency($dataTerjual->pendapatan),
]; ];
} }
return null; return null; // Filter out
})->filter(); })->filter();
$filterInfo = $this->helper->buildNampanFilterInfo($startDate, $endDate, $params); $filterInfo = $this->helper->buildNampanFilterInfo($startDate, $endDate, $params); // FIXED: Range
return [ return [
'filter' => $filterInfo, 'filter' => $filterInfo,
@ -420,6 +405,7 @@ class LaporanService
]; ];
} }
private function getAllSalesNames(): Collection private function getAllSalesNames(): Collection
{ {
return Cache::remember('all_sales_names', self::CACHE_TTL, function () { return Cache::remember('all_sales_names', self::CACHE_TTL, function () {
@ -448,7 +434,7 @@ class LaporanService
$nampanId = (int) $params['nampan_id']; $nampanId = (int) $params['nampan_id'];
if ($nampanId === -1) { if ($nampanId === -1) {
$query->where('item_transaksis.posisi_asal', 'Brankas'); $query->where('item_transaksis.posisi_asal', 'Brankas');
} elseif ($nampanId > 0) { } elseif ($nampanId > 0) { // FIXED: >0 join, 0 skip (all)
$query->join('nampans', function ($join) use ($nampanId) { $query->join('nampans', function ($join) use ($nampanId) {
$join->on('item_transaksis.posisi_asal', '=', 'nampans.nama') $join->on('item_transaksis.posisi_asal', '=', 'nampans.nama')
->where('nampans.id', $nampanId); ->where('nampans.id', $nampanId);