sum('grandtotal'); return view('gudang.dashboard', $data); } public function produksitambah() { return view('gudang.produksitambah'); } public function produksisimpan(Request $request) { $request->validate([ 'tanggalproduksi' => 'required|date', 'namaproduk' => 'required|string|max:255', 'stok' => 'required|integer|min:1', 'hppestimasi' => 'required|numeric|min:0', 'deskripsi' => 'nullable|string', 'fotoproduk' => 'nullable|image|mimes:jpg,jpeg,png|max:2048', ]); $filename = null; if ($request->hasFile('fotoproduk')) { $file = $request->file('fotoproduk'); $filename = Str::uuid() . '.' . $file->getClientOriginalExtension(); $file->move(public_path('uploads/foto_produk'), $filename); } ProduksiModel::create([ 'tanggalproduksi' => $request->tanggalproduksi, 'namaproduk' => $request->namaproduk, 'stok' => $request->stok, 'stok_awal' => $request->stok, 'stok_tambahan' => 0, 'tanggal_update' => null, 'hppestimasi' => $request->hppestimasi, 'deskripsiproduk' => $request->deskripsi, 'fotoproduk' => $filename, 'status' => 'Menunggu', 'hppfinal' => null, 'hargajual' => null, 'tanggalselesai' => null, ]); return redirect('gudang/produksidaftar')->with('success', 'Data produksi berhasil disimpan.'); } public function produksidaftar() { $produksi = ProduksiModel::all(); return view('gudang.produksidaftar', compact('produksi')); } // ✅ Edit produksi public function produksiedit($id) { $produksi = ProduksiModel::findOrFail($id); // cegah edit jika sudah disetujui owner if ($produksi->status !== 'Menunggu') { return redirect('gudang/produksidaftar')->with('error', 'Produksi sudah diproses dan tidak bisa diedit.'); } return view('gudang.produksiedit', compact('produksi')); } // ✅ Update produksi public function produksiupdate(Request $request, $id) { $produksi = ProduksiModel::findOrFail($id); // Hanya bisa update jika masih menunggu if ($produksi->status !== 'Menunggu') { return redirect('gudang/produksidaftar')->with('error', 'Produksi sudah diproses dan tidak bisa diubah.'); } $request->validate([ 'namaproduk' => 'required|string|max:255', 'hppestimasi' => 'required|numeric|min:0', 'deskripsi' => 'nullable|string', 'fotoproduk' => 'nullable|image|mimes:jpg,jpeg,png|max:2048', ]); if ($request->hasFile('fotoproduk')) { // Hapus file lama jika ada if ($produksi->fotoproduk && file_exists(public_path('uploads/foto_produk/' . $produksi->fotoproduk))) { unlink(public_path('uploads/foto_produk/' . $produksi->fotoproduk)); } $file = $request->file('fotoproduk'); $filename = Str::uuid() . '.' . $file->getClientOriginalExtension(); $file->move(public_path('uploads/foto_produk'), $filename); $produksi->fotoproduk = $filename; } $produksi->namaproduk = $request->namaproduk; $produksi->hppestimasi = $request->hppestimasi; $produksi->deskripsiproduk = $request->deskripsi; $produksi->tanggal_update = \Carbon\Carbon::now(); $produksi->status = 'Menunggu'; $produksi->hppfinal = null; $produksi->hargajual = null; $produksi->tanggalselesai = null; $produksi->save(); return redirect('gudang/produksidaftar')->with('success', 'Data produksi berhasil diperbarui.'); } // Form untuk tambah jumlah produksi public function produksitambahjumlah($id) { $produksi = ProduksiModel::findOrFail($id); // hanya produk dengan status selesai yang bisa ditambah if ($produksi->status !== 'Selesai') { return redirect('gudang/produksidaftar')->with('error', 'Produksi belum selesai dan tidak bisa ditambah stok.'); } return view('gudang.produksitambahjumlah', compact('produksi')); } // Menyimpan jumlah tambahan produksi public function produksisimpanjumlah(Request $request, $id) { $produksi = ProduksiModel::findOrFail($id); // Hanya boleh tambah jika status SELESAI if ($produksi->status !== 'Selesai') { return redirect('gudang/produksidaftar')->with('error', 'Produksi belum selesai dan tidak bisa ditambah stok.'); } $request->validate([ 'stok_tambahan' => 'required|integer|min:1', ]); // ✅ Simpan jumlah awal hanya sekali if (is_null($produksi->stok_awal)) { $produksi->stok_awal = $produksi->stok; $produksi->stok_tambahan = 0; } // Tambahan jumlah_tambahan $produksi->stok_tambahan += $request->stok_tambahan; // Update jumlah total $produksi->stok = $produksi->stok_awal + $produksi->stok_tambahan; // Reset data hasil review Owner $produksi->status = 'Menunggu'; $produksi->hppfinal = null; $produksi->hargajual = null; $produksi->tanggalselesai = null; $produksi->tanggal_update = now(); $produksi->save(); // ✅ Sinkronisasi stok showroom jika sudah pernah masuk showroom $showroom = ShowroomModel::where('idproduk', $produksi->idproduksi)->first(); if ($showroom) { $showroom->stok_awal = $produksi->stok; $showroom->stok_sisa = $produksi->stok - $showroom->stok_terjual; $showroom->save(); } return redirect('gudang/produksidaftar')->with('success', 'Stok produksi berhasil ditambahkan.'); } public function showroomdaftar() { $data['showroom'] = ShowroomModel::with('produksi')->orderBy('tanggalmasuk', 'desc')->get(); return view('gudang.showroomdaftar', $data); } public function penjualandaftar() { $data['penjualan'] = PenjualanModel::with('penjualandetail')->orderBy('tanggalpenjualan', 'desc')->get(); return view('gudang.penjualandaftar', $data); } public function opnamedaftar() { $data = ShowroomModel::with('produksi')->get(); return view('gudang.stokopnamedaftar', compact('data')); } // Form tambah opname berdasarkan showroom ID public function opnametambah($id) { $showroom = ShowroomModel::with('produksi')->findOrFail($id); return view('gudang.stokopnametambah', compact('showroom')); } // Simpan hasil opname public function opnamesimpan(Request $request) { $request->validate([ 'showroom_id' => 'required|exists:showroom,idshowroom', 'tanggal_opname' => 'required|date', 'stok_fisik' => 'required|integer|min:0', 'keterangan' => 'nullable|string', ]); $showroom = ShowroomModel::findOrFail($request->showroom_id); $stok_sistem = $showroom->stok_sisa; $stok_fisik = $request->stok_fisik; $selisih = $stok_fisik - $stok_sistem; StokOpnameModel::create([ 'showroom_id' => $request->showroom_id, 'tanggal_opname' => $request->tanggal_opname, 'stok_sistem' => $stok_sistem, 'stok_fisik' => $stok_fisik, 'selisih' => $selisih, 'keterangan' => $request->keterangan, ]); return redirect()->route('stokopname.daftar')->with('success', 'Stok opname berhasil disimpan.'); } public function opnameriwayat() { $data = StokOpnameModel::with('showroom.produksi')->latest()->get(); return view('gudang.stokopnameriwayat', compact('data')); } public function laporanproduksi() { $data = ProduksiModel::latest()->get(); return view('gudang.laporanproduksi', compact('data')); } public function exportPdfProduksi() { $data = ProduksiModel::latest()->get(); $pdf = Pdf::loadView('gudang.laporanproduksi_pdf', compact('data')) ->setPaper('A4', 'landscape'); return $pdf->download('Laporan-Produksi-' . now()->format('d-m-Y') . '.pdf'); } public function exportExcelProduksi() { $data = ProduksiModel::latest()->get(); $tanggal = \Carbon\Carbon::now()->format('d-m-Y'); $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); // Header $sheet->fromArray([ ['No', 'Nama Produk', 'Tanggal Produksi', 'Stok Awal', 'Stok Tambahan', 'Stok Total', 'HPP Final', 'Harga Jual', 'Status'] ], null, 'A1'); // Data $row = 2; foreach ($data as $index => $item) { $sheet->setCellValue("A{$row}", $index + 1); $sheet->setCellValue("B{$row}", $item->namaproduk); $sheet->setCellValue("C{$row}", \Carbon\Carbon::parse($item->tanggalproduksi)->format('d-m-Y')); $sheet->setCellValue("D{$row}", $item->stok_awal); $sheet->setCellValue("E{$row}", $item->stok_tambahan); $sheet->setCellValue("F{$row}", $item->stok); // Total stok $sheet->setCellValue("G{$row}", $item->hppfinal ?? '-'); $sheet->setCellValue("H{$row}", $item->hargajual ?? '-'); $sheet->setCellValue("I{$row}", ucfirst($item->status)); $row++; } $filename = 'Laporan-Produksi-' . $tanggal . '.xlsx'; return new StreamedResponse(function () use ($spreadsheet) { $writer = new Xlsx($spreadsheet); $writer->save('php://output'); }, 200, [ 'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'Content-Disposition' => 'attachment;filename="' . $filename . '"', 'Cache-Control' => 'max-age=0', ]); } public function laporanstokopname() { $data = StokOpnameModel::with('showroom.produksi')->latest()->get(); return view('gudang.laporanstokopname', compact('data')); } public function exportPdfStokOpname() { $data = StokOpnameModel::with('showroom.produksi')->latest()->get(); $tanggal = \Carbon\Carbon::now()->format('d-m-Y'); $pdf = Pdf::loadView('gudang.laporanstokopname_pdf', compact('data')) ->setPaper('A4', 'landscape'); return Pdf::loadView('gudang.laporanstokopname_pdf', compact('data')) ->download('Laporan-Stok-Opname-' . now()->format('d-m-Y') . '.pdf'); } public function exportExcelStokOpname() { $data = StokOpnameModel::with('showroom.produksi')->latest()->get(); $tanggal = \Carbon\Carbon::now()->format('d-m-Y'); $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); // Header $sheet->setCellValue('A1', 'No'); $sheet->setCellValue('B1', 'Nama Produk'); $sheet->setCellValue('C1', 'Tanggal Opname'); $sheet->setCellValue('D1', 'Stok Sistem'); $sheet->setCellValue('E1', 'Stok Fisik'); $sheet->setCellValue('F1', 'Selisih'); $sheet->setCellValue('G1', 'Keterangan'); // Data $row = 2; foreach ($data as $index => $item) { $sheet->setCellValue('A' . $row, $index + 1); $sheet->setCellValue('B' . $row, $item->showroom->produksi->namaproduk ?? '-'); $sheet->setCellValue('C' . $row, Carbon::parse($item->tanggal_opname)->format('d-m-Y')); $sheet->setCellValue('D' . $row, $item->stok_sistem); $sheet->setCellValue('E' . $row, $item->stok_fisik); $sheet->setCellValue('F' . $row, $item->selisih); $sheet->setCellValue('G' . $row, $item->keterangan ?? '-'); $row++; } // Filename otomatis dengan tanggal $filename = 'Laporan-Stok-Opname-' . $tanggal . '.xlsx'; // Download return new StreamedResponse(function () use ($spreadsheet) { $writer = new Xlsx($spreadsheet); $writer->save('php://output'); }, 200, [ 'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'Content-Disposition' => 'attachment;filename="' . $filename . '"', 'Cache-Control' => 'max-age=0', ]); } // ✅ Batalkan produksi //public function produksibatalkan($id) //{ //$produksi = ProduksiModel::findOrFail($id); //if (in_array($produksi->status, ['Selesai', 'Dibatalkan'])) { //return redirect('gudang/produksidaftar')->with('error', 'Produksi yang sudah selesai tidak bisa dibatalkan.'); //} //$produksi->status = 'Dibatalkan'; //$produksi->save(); //return redirect('gudang/produksidaftar')->with('success', 'Produksi berhasil dibatalkan.'); //} public function produkdaftar() { $data['produk'] = ProdukModel::all(); return view('gudang.produkdaftar', $data); } //public function stockopnamedaftar() //{ //$stockOpnameDates = StockopnameModel::select('tanggalstockopname') //->distinct() //->orderBy('tanggalstockopname', 'DESC') //->paginate(6); //$produk = ProdukModel::all(); //$stockOpnameData = []; //foreach ($stockOpnameDates as $date) { //$tanggalStockOpname = $date->tanggalstockopname; //$stockOpnameData[$tanggalStockOpname] = StockopnameModel::with('produk') //->where('tanggalstockopname', $tanggalStockOpname) //->get(); //} //return view('gudang.stockopnamedaftar', compact('stockOpnameDates', 'produk', 'stockOpnameData')); //} //public function stockopnamesimpan(Request $request) //{ //if ($request->isMethod('post')) { //$tanggalStockOpname = $request->input('tanggalstockopname'); //$idProduk = $request->input('idproduk'); //$stokSistem = $request->input('stoksistem'); //$stokGudang = $request->input('stokgudang'); //$selisih = $request->input('selisih'); //for ($i = 0; $i < count($idProduk); $i++) { //if (!empty($idProduk[$i])) { //$produk = ProdukModel::withTrashed()->find($idProduk[$i]); //if ($produk) { //StockopnameModel::create([ //'tanggalstockopname' => $tanggalStockOpname, //'idproduk' => $idProduk[$i], //'stoksistem' => $stokSistem[$i] ?? 0, //'stokgudang' => $stokGudang[$i] ?? 0, //'selisih' => $selisih[$i] ?? 0, //'waktuinputstockopname' => now() //]); //} //} //} //return redirect('gudang/stockopnamedaftar') //->with('success', 'Stock Opname berhasil disimpan'); //} //} //public function stockopnamehapus($tanggalstockopname) //{ //StockopnameModel::where('tanggalstockopname', $tanggalstockopname)->delete(); //return redirect('gudang/stockopnamedaftar') // ->with('success', 'Data Stock Opname berhasil dihapus'); // } public function getProdukByBarcode(Request $request, $barcode) { $produk = ProdukModel::where('barcode', $barcode)->first(); if ($produk) { return response()->json([ 'success' => true, 'data' => $produk ]); } else { return response()->json([ 'success' => false, 'message' => 'Produk tidak ditemukan' ]); } } public function profile() { return view('gudang.profile'); } public function profileupdate(Request $request) { /** @var \App\Models\User $user */ $user = Auth::user(); $request->validate([ 'name' => 'required', 'email' => 'required|email|unique:users,email,' . $user->id, ]); $data = [ 'name' => $request->name, 'email' => $request->email, ]; if (!empty($request->password)) { $data['password'] = bcrypt($request->password); } $user->update($data); return redirect('gudang/profile')->with('success', 'Profile berhasil diupdate'); } // barangkeluar public function barangkeluardaftar() { $data['penjualan'] = PenjualanModel::with(['penjualandetail']) ->groupBy('notajual') ->orderBy('tanggalpenjualan', 'desc') ->get(); // return response()->Json($data); return view('gudang.barangkeluardaftar', $data); } public function barangkeluarproses($notajual) { DB::table('penjualan')->where('notajual', $notajual)->update([ 'statusgudang' => 'Proses', ]); return back()->with('success', 'Data barang keluar berhasil diproses.'); } public function barangkeluarselesai($notajual) { DB::table('penjualan')->where('notajual', $notajual)->update([ 'statusgudang' => 'Selesai', ]); return back()->with('success', 'Data barang keluar berhasil diselesaikan.'); } public function updatecustomproduk(Request $request) { $idDetails = $request->idpenjualan; $customs = $request->custom; foreach ($idDetails as $index => $id) { DB::table('penjualan')->where('idpenjualan', $id)->update([ 'custom' => $customs[$index], ]); } return back()->with('success', 'Data custom produk berhasil diperbarui.'); } public function barangkeluartambah() { $data['produk'] = ProdukModel::all(); return view('gudang.barangkeluartambah', $data); } public function barangkeluarsimpan(Request $request) { $request->validate([ 'tanggalpenjualan' => 'required|date', 'grandtotalnon' => 'required|numeric', 'uangpembeli' => 'nullable|numeric', 'kembalian' => 'required|numeric', 'diskon' => 'nullable|numeric', 'metodepembayaran' => 'required|string', 'namabarang' => 'required|array', 'namabarang.*' => 'string', 'harga' => 'required|array', 'harga.*' => 'numeric', 'jumlah' => 'required|array', 'jumlah.*' => 'integer|min:1', 'total' => 'required|array', 'total.*' => 'numeric' ]); try { DB::beginTransaction(); $tanggalPenjualan = $request->tanggalpenjualan; $grandTotal = $request->grandtotalnon; $uangPembeli = $request->uangpembeli ?? 0; $kembalian = $request->kembalian; $notaJual = now()->format('YmdHis'); $kodeNota = $this->getKodeNota($tanggalPenjualan); $diskon = $request->diskon ?? 0; $metodePembayaran = $request->metodepembayaran; $statusTransaksi = 'Menunggu Konfirmasi gudang'; foreach ($request->namabarang as $i => $namaBarang) { $harga = $request->harga[$i]; $jumlah = $request->jumlah[$i]; $total = $request->total[$i]; // Simpan penjualan PenjualanModel::create([ 'notajual' => $notaJual, 'kodenota' => $kodeNota, 'namabarang' => $namaBarang, 'harga' => $harga, 'jumlah' => $jumlah, 'total' => $total, 'tanggalpenjualan' => $tanggalPenjualan, 'grandtotal' => $grandTotal, 'uangpembeli' => $uangPembeli, 'kembalian' => $kembalian, 'diskon' => $diskon, 'metodepembayaran' => $metodePembayaran, 'statustransaksi' => $statusTransaksi ]); // Update stok produk ProdukModel::where('namaproduk', $namaBarang)->decrement('stok', $jumlah); } DB::commit(); return redirect('gudang/cetaknota/' . $notaJual)->with('success', 'Penjualan Barang Berhasil Disimpan'); } catch (\Exception $e) { DB::rollback(); return back()->with('error', $e->getMessage()); } } private function getKodeNota($tanggalPenjualan) { $tahun = date('Y', strtotime($tanggalPenjualan)); $baseCode = $tahun . '1'; $lastNota = PenjualanModel::whereYear('tanggalpenjualan', $tahun) ->orderByDesc('idpenjualan') ->first(); if ($lastNota) { return $tahun . ((int)substr($lastNota->kodenota, 4) + 1); } return $baseCode; } public function cetakstrukgudang($id) { $penjualan = DB::table('penjualan') ->where('notajual', $id) ->get(); if ($penjualan->isEmpty()) { return back()->with('error', 'Nota tidak ditemukan'); } $pecah = $penjualan->first(); $subtotal = $penjualan->sum('total'); // Ambil DP, default 0 jika tidak ada $dp = $pecah->dp ?? 0; // Hitung Grand Total: subtotal - diskon (%) - dp $grandtotal = $subtotal - ($subtotal * $pecah->diskon / 100) - $dp; // Kirim semua data yang dibutuhkan ke view $pdf = Pdf::loadView('gudang.cetakstrukgudang', compact( 'penjualan', 'pecah', 'subtotal', 'dp', 'grandtotal' ))->setPaper('A4', 'portrait'); return $pdf->stream("Struk_Gudang_{$id}.pdf"); } public function cetakstrukcustom($id) { $penjualan = DB::table('penjualan') ->where('notajual', $id) ->get(); if ($penjualan->isEmpty()) { return back()->with('error', 'Nota tidak ditemukan'); } $pecah = $penjualan->first(); $subtotal = $penjualan->sum('total'); return view('gudang.cetakstrukcustom', compact('penjualan', 'pecah', 'subtotal')); } public function cetakNota($id) { $penjualan = PenjualanModel::where('notajual', $id)->get(); if ($penjualan->isEmpty()) { return back()->with('error', 'Nota tidak ditemukan'); } $pecah = $penjualan->first(); // Ambil data pertama $subtotal = $penjualan->sum('total'); return view('gudang.cetaknota', compact('penjualan', 'pecah', 'subtotal')); } public function cetakfaktur($id) { $penjualan = PenjualanModel::with(['produk'])->where('notajual', $id)->get(); // return response()->json($penjualan); if ($penjualan->isEmpty()) { return back()->with('error', 'Nota tidak ditemukan'); } $pecah = $penjualan->first(); // Ambil data pertama $subtotal = $penjualan->sum('total'); $grandtotal = $subtotal - ($subtotal * $pecah->diskon / 100); return view('gudang.cetakfaktur', compact('penjualan', 'pecah', 'subtotal', 'grandtotal')); } public function ubahstatustransaksi(Request $request) { PenjualanModel::where('notajual', $request->notajual)->update([ 'statustransaksi' => $request->statustransaksi ]); return back()->with('success', 'Status Transaksi Berhasil Diubah'); } public function barangkeluarhapus($id) { PenjualanModel::where('notajual', $id)->delete(); return back()->with('success', 'Barang Keluar Berhasil Dihapus'); } }