diff --git a/app/Http/Controllers/LaporanController.php b/app/Http/Controllers/LaporanController.php
new file mode 100644
index 0000000..e7e09b7
--- /dev/null
+++ b/app/Http/Controllers/LaporanController.php
@@ -0,0 +1,176 @@
+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;
+ });
+ }
+}
\ No newline at end of file
diff --git a/database/factories/TransaksiFactory.php b/database/factories/TransaksiFactory.php
index 81b6cfb..999c8bb 100644
--- a/database/factories/TransaksiFactory.php
+++ b/database/factories/TransaksiFactory.php
@@ -22,6 +22,7 @@ class TransaksiFactory extends Factory
$sales = Sales::inRandomOrder()->first();
$kasir = User::inRandomOrder()->first();
+ $date = $this->faker->dateTimeBetween('-3 months');
return [
'id_kasir' => $kasir?->id,
'id_sales' => $sales?->id,
@@ -31,7 +32,8 @@ class TransaksiFactory extends Factory
'alamat' => $this->faker->address(),
'ongkos_bikin' => $this->faker->randomFloat(2, 0, 1000000),
'total_harga' => $this->faker->randomFloat(2, 100000, 5000000),
- 'created_at' => now(),
+ 'created_at' => $date,
+ 'updated_at' => $date,
];
}
}
diff --git a/resources/js/components/InputField.vue b/resources/js/components/InputField.vue
index b82db89..053e2b5 100644
--- a/resources/js/components/InputField.vue
+++ b/resources/js/components/InputField.vue
@@ -4,7 +4,7 @@
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
:placeholder="placeholder"
- class="mt-1 block w-full rounded-md shadow-sm sm:text-sm bg-A text-D border-B focus:border-C focus:ring focus:ring-D focus:ring-opacity-50 p-2"
+ class="mt-1 block w-full rounded-md shadow-sm sm:text-sm bg-A text-D border-B focus:border-C focus:ring focus:outline-none focus:ring-D focus:ring-opacity-50 p-2"
/>
diff --git a/resources/js/components/InputPassword.vue b/resources/js/components/InputPassword.vue
new file mode 100644
index 0000000..4efe49d
--- /dev/null
+++ b/resources/js/components/InputPassword.vue
@@ -0,0 +1,46 @@
+
+
Tanggal | +Nama Sales | +Jumlah Item Terjual | +Total Berat Terjual | +Total Pendapatan | +
---|---|---|---|---|
+
+
+ Memuat data...
+
+ |
+ ||||
Tidak ada data untuk ditampilkan. | +||||
{{ + item.tanggal }} | +{{ item.sales[0].nama }} | +{{ item.sales[0].item_terjual }} | +{{ item.sales[0].berat_terjual }} | +
+
+ {{ item.sales[0].pendapatan }}
+
+ |
+
{{ sales.nama }} | +{{ sales.item_terjual }} | +{{ sales.berat_terjual }} | +
+
+ {{ sales.pendapatan }}
+
+ |
+ |
Total | +{{ item.total_item_terjual }} | +{{ item.total_berat }} | +
+
+ {{ item.total_pendapatan }}
+
+ |
+ |
{{ item.tanggal }} | +Tidak ada transaksi + pada hari ini | +
Tanggal | +Nama Sales | +Jumlah Item Terjual | +Total Berat Terjual | +Total Pendapatan | +
---|---|---|---|---|
+
+
+ Memuat data...
+
+ |
+ ||||
Tidak ada data untuk ditampilkan. | +||||
{{ + item.tanggal }} | +{{ item.sales[0].nama }} | +{{ item.sales[0].item_terjual }} | +{{ item.sales[0].berat_terjual }} | +
+
+ {{ item.sales[0].pendapatan }}
+
+ |
+
{{ sales.nama }} | +{{ sales.item_terjual }} | +{{ sales.berat_terjual }} | +
+
+ {{ sales.pendapatan }}
+
+ |
+ |
Total | +{{ item.total_item_terjual }} | +{{ item.total_berat }} | +
+
+ {{ item.total_pendapatan }}
+
+ |
+ |
{{ item.tanggal }} | +Tidak ada transaksi + pada hari ini | +
Produk Baru
@@ -131,6 +130,7 @@ import InputField from "../components/InputField.vue"; import InputSelect from "../components/InputSelect.vue"; import CreateItemModal from "../components/CreateItemModal.vue"; + const router = useRouter(); const form = ref({ diff --git a/resources/js/pages/Kasir.vue b/resources/js/pages/Kasir.vue index cb19e0d..074f3ad 100644 --- a/resources/js/pages/Kasir.vue +++ b/resources/js/pages/Kasir.vue @@ -1,7 +1,7 @@Laporan
+ +