478 lines
16 KiB
PHP
478 lines
16 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\Paket;
|
|
use App\Models\StockModel;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Str;
|
|
|
|
class PaketController extends Controller
|
|
{
|
|
public function __construct()
|
|
{
|
|
$this->middleware('auth');
|
|
// Terapkan middleware admin hanya untuk method yang membutuhkan akses admin
|
|
$this->middleware('admin')->only([
|
|
'create', 'store', 'edit', 'update', 'destroy', 'activate',
|
|
'tambahBarang', 'updateJumlah'
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Menampilkan daftar paket
|
|
*/
|
|
public function index()
|
|
{
|
|
$pakets = Paket::with('barangs')->get();
|
|
return view('paket', compact('pakets'));
|
|
}
|
|
|
|
/**
|
|
* Menampilkan form untuk membuat paket baru
|
|
*/
|
|
public function create()
|
|
{
|
|
// Ambil data barang yang masih ada stoknya
|
|
$barangs = StockModel::where('stok', '>', 0)->get();
|
|
return view('tambah-paket', compact('barangs'));
|
|
}
|
|
|
|
/**
|
|
* Menyimpan paket baru
|
|
*/
|
|
public function store(Request $request)
|
|
{
|
|
$request->validate([
|
|
'nama_paket' => 'required|string|max:255',
|
|
'jenis_paket' => 'required|in:wedding,seminar,outdoor,custom',
|
|
'harga' => 'required|numeric|min:0',
|
|
'stok' => 'required|integer|min:1',
|
|
'keterangan' => 'nullable|string',
|
|
'image' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048',
|
|
'ongkir.*.nama_kota' => 'nullable|string|max:255',
|
|
'ongkir.*.biaya_ongkir' => 'nullable|numeric|min:0',
|
|
]);
|
|
|
|
try {
|
|
DB::beginTransaction();
|
|
|
|
// Upload gambar jika ada
|
|
$imagePath = null;
|
|
if ($request->hasFile('image')) {
|
|
$imagePath = $request->file('image')->store('paket-images', 'public');
|
|
}
|
|
|
|
// Simpan data paket
|
|
$paket = Paket::create([
|
|
'nama_paket' => $request->nama_paket,
|
|
'jenis_paket' => $request->jenis_paket,
|
|
'harga' => $request->harga,
|
|
'stok' => $request->stok,
|
|
'keterangan' => $request->keterangan,
|
|
'image' => $imagePath,
|
|
'status' => 'aktif'
|
|
]);
|
|
|
|
// Simpan data ongkir kota
|
|
if ($request->has('ongkir')) {
|
|
foreach ($request->ongkir as $ongkir) {
|
|
if (!empty($ongkir['nama_kota']) && !empty($ongkir['biaya_ongkir'])) {
|
|
$paket->ongkirKota()->create([
|
|
'nama_kota' => $ongkir['nama_kota'],
|
|
'biaya_ongkir' => $ongkir['biaya_ongkir'],
|
|
'status' => true
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Tambahkan detail_barang (array barang yang dipilih)
|
|
$detailBarang = [];
|
|
if ($request->has('barang_ids')) {
|
|
foreach ($request->barang_ids as $barangId) {
|
|
$jumlah = $request->input('jumlah_' . $barangId, 1);
|
|
$barang = StockModel::find($barangId);
|
|
if ($barang) {
|
|
$detailBarang[] = [
|
|
'id' => $barang->id,
|
|
'nama_barang' => $barang->nama_barang,
|
|
'kode_barang' => $barang->kode_barang,
|
|
'kategori' => $barang->kategori,
|
|
'harga_sewa' => $barang->harga_sewa,
|
|
'jumlah' => $jumlah,
|
|
'deskripsi' => $barang->deskripsi,
|
|
];
|
|
}
|
|
}
|
|
$paket->detail_barang = $detailBarang;
|
|
$paket->save();
|
|
}
|
|
|
|
DB::commit();
|
|
return redirect()->route('paket.index')->with('success', 'Paket berhasil ditambahkan');
|
|
} catch (\Exception $e) {
|
|
DB::rollback();
|
|
return back()->with('error', 'Terjadi kesalahan: ' . $e->getMessage())->withInput();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Menampilkan form untuk mengedit paket
|
|
*/
|
|
public function edit($id)
|
|
{
|
|
$paket = Paket::with(['barangs', 'ongkirKota'])->findOrFail($id);
|
|
$barangs = StockModel::all();
|
|
return view('edit-paket', compact('paket', 'barangs'));
|
|
}
|
|
|
|
/**
|
|
* Update data paket
|
|
*/
|
|
public function update(Request $request, $id)
|
|
{
|
|
$request->validate([
|
|
'nama_paket' => 'required|string|max:255',
|
|
'jenis_paket' => 'required|string|in:wedding,seminar,outdoor,custom',
|
|
'harga' => 'required|numeric|min:0',
|
|
'image' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048',
|
|
'keterangan' => 'nullable|string',
|
|
'stok' => 'required|integer|min:0',
|
|
'ongkir.*.nama_kota' => 'nullable|string|max:255',
|
|
'ongkir.*.biaya_ongkir' => 'nullable|numeric|min:0',
|
|
]);
|
|
|
|
try {
|
|
DB::beginTransaction();
|
|
|
|
$paket = Paket::findOrFail($id);
|
|
|
|
// Upload gambar jika ada
|
|
if ($request->hasFile('image')) {
|
|
// Hapus gambar lama
|
|
if ($paket->image) {
|
|
Storage::disk('public')->delete($paket->image);
|
|
}
|
|
$imagePath = $request->file('image')->store('pakets', 'public');
|
|
$paket->image = $imagePath;
|
|
}
|
|
|
|
$paket->update([
|
|
'nama_paket' => $request->nama_paket,
|
|
'jenis_paket' => $request->jenis_paket,
|
|
'harga' => $request->harga,
|
|
'keterangan' => $request->keterangan,
|
|
'stok' => $request->stok
|
|
]);
|
|
|
|
// Update ongkir kota
|
|
if ($request->has('ongkir')) {
|
|
// Hapus data ongkir yang lama
|
|
$paket->ongkirKota()->delete();
|
|
|
|
// Tambah data ongkir yang baru
|
|
foreach ($request->ongkir as $ongkir) {
|
|
if (!empty($ongkir['nama_kota']) && !empty($ongkir['biaya_ongkir'])) {
|
|
$paket->ongkirKota()->create([
|
|
'nama_kota' => $ongkir['nama_kota'],
|
|
'biaya_ongkir' => $ongkir['biaya_ongkir'],
|
|
'status' => true
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update detail_barang (array barang yang dipilih)
|
|
$detailBarang = [];
|
|
if ($request->has('barang_ids')) {
|
|
foreach ($request->barang_ids as $barangId) {
|
|
$jumlah = $request->input('jumlah_' . $barangId, 1);
|
|
$barang = StockModel::find($barangId);
|
|
if ($barang) {
|
|
$detailBarang[] = [
|
|
'id' => $barang->id,
|
|
'nama_barang' => $barang->nama_barang,
|
|
'kode_barang' => $barang->kode_barang,
|
|
'kategori' => $barang->kategori,
|
|
'harga_sewa' => $barang->harga_sewa,
|
|
'jumlah' => $jumlah,
|
|
'deskripsi' => $barang->deskripsi,
|
|
];
|
|
}
|
|
}
|
|
$paket->detail_barang = $detailBarang;
|
|
$paket->save();
|
|
}
|
|
|
|
DB::commit();
|
|
return redirect()->route('paket.index')->with('success', 'Paket berhasil diperbarui!');
|
|
|
|
} catch (\Exception $e) {
|
|
DB::rollback();
|
|
return back()->with('error', 'Terjadi kesalahan: ' . $e->getMessage())->withInput();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Hapus paket
|
|
*/
|
|
public function destroy($id)
|
|
{
|
|
try {
|
|
DB::beginTransaction();
|
|
|
|
$paket = Paket::findOrFail($id);
|
|
|
|
// Hapus gambar jika ada
|
|
if ($paket->image) {
|
|
Storage::disk('public')->delete($paket->image);
|
|
}
|
|
|
|
// Kembalikan stok barang
|
|
foreach ($paket->barangs as $barang) {
|
|
$jumlah = $barang->pivot->jumlah;
|
|
$barang->increment('stok', $jumlah);
|
|
}
|
|
|
|
$paket->delete();
|
|
|
|
DB::commit();
|
|
return redirect()->route('paket.index')->with('success', 'Paket berhasil dihapus!');
|
|
|
|
} catch (\Exception $e) {
|
|
DB::rollback();
|
|
return back()->with('error', 'Terjadi kesalahan: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Mendapatkan daftar barang dalam paket
|
|
*/
|
|
public function getBarang($id)
|
|
{
|
|
try {
|
|
$paket = Paket::with('barangs')->findOrFail($id);
|
|
|
|
$result = [];
|
|
foreach ($paket->barangs as $barang) {
|
|
$result[] = [
|
|
'id' => $barang->pivot->id,
|
|
'barang_id' => $barang->id,
|
|
'nama_barang' => $barang->nama_barang,
|
|
'kode_barang' => $barang->kode_barang,
|
|
'kategori' => $barang->kategori,
|
|
'harga_sewa' => $barang->harga_sewa,
|
|
'stok' => $barang->stok,
|
|
'jumlah' => $barang->pivot->jumlah,
|
|
'image_url' => $barang->image_url
|
|
];
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'data' => $result
|
|
]);
|
|
|
|
} catch (\Exception $e) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Terjadi kesalahan: ' . $e->getMessage()
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Menambahkan barang ke paket
|
|
*/
|
|
public function tambahBarang(Request $request, $id)
|
|
{
|
|
$request->validate([
|
|
'barang_id' => 'required|exists:barangs,id',
|
|
'jumlah' => 'required|integer|min:1',
|
|
]);
|
|
|
|
try {
|
|
DB::beginTransaction();
|
|
|
|
$paket = Paket::findOrFail($id);
|
|
$barang = StockModel::findOrFail($request->barang_id);
|
|
|
|
// Validasi stok
|
|
if ($barang->stok < $request->jumlah) {
|
|
throw new \Exception("Stok barang {$barang->nama_barang} tidak mencukupi");
|
|
}
|
|
|
|
// Cek apakah barang sudah ada dalam paket
|
|
$existing = $paket->barangs()->where('barang_id', $request->barang_id)->first();
|
|
|
|
if ($existing) {
|
|
// Update jumlah jika sudah ada
|
|
$oldJumlah = $existing->pivot->jumlah;
|
|
$selisih = $request->jumlah - $oldJumlah;
|
|
|
|
if ($selisih > 0 && $barang->stok < $selisih) {
|
|
throw new \Exception("Stok barang {$barang->nama_barang} tidak mencukupi");
|
|
}
|
|
|
|
$paket->barangs()->updateExistingPivot($request->barang_id, [
|
|
'jumlah' => $request->jumlah
|
|
]);
|
|
|
|
// Update stok barang
|
|
$barang->decrement('stok', $selisih);
|
|
} else {
|
|
// Tambahkan baru jika belum ada
|
|
$paket->barangs()->attach($request->barang_id, [
|
|
'jumlah' => $request->jumlah
|
|
]);
|
|
|
|
// Kurangi stok barang
|
|
$barang->decrement('stok', $request->jumlah);
|
|
}
|
|
|
|
DB::commit();
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Barang berhasil ditambahkan ke paket',
|
|
'data' => [
|
|
'nama_barang' => $barang->nama_barang,
|
|
'jumlah' => $request->jumlah,
|
|
'stok_tersisa' => $barang->stok
|
|
]
|
|
]);
|
|
|
|
} catch (\Exception $e) {
|
|
DB::rollback();
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Terjadi kesalahan: ' . $e->getMessage()
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
public function updateJumlah(Request $request, $id)
|
|
{
|
|
try {
|
|
$paket = Paket::findOrFail($id);
|
|
|
|
$request->validate([
|
|
'jumlah' => 'required|integer|min:1'
|
|
]);
|
|
|
|
// Update detail_barang dengan jumlah baru
|
|
if ($paket->detail_barang) {
|
|
$detail_barang = $paket->detail_barang;
|
|
foreach ($detail_barang as &$barang) {
|
|
$barang['jumlah'] = $request->jumlah;
|
|
}
|
|
$paket->detail_barang = $detail_barang;
|
|
$paket->save();
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Jumlah berhasil diperbarui'
|
|
]);
|
|
} catch (\Exception $e) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Gagal memperbarui jumlah: ' . $e->getMessage()
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Mengaktifkan satu unit paket yang sedang disewa
|
|
*/
|
|
public function activate($id)
|
|
{
|
|
try {
|
|
DB::beginTransaction();
|
|
|
|
$paket = Paket::findOrFail($id);
|
|
|
|
// Ambil sewa yang paling lama (terlama) untuk diaktifkan
|
|
$oldestSewa = $paket->sewas()
|
|
->whereIn('status', ['confirmed', 'ongoing'])
|
|
->orderBy('tanggal_mulai', 'asc')
|
|
->first();
|
|
|
|
if (!$oldestSewa) {
|
|
return redirect()->route('paket.index')->with('error', 'Tidak ada penyewaan aktif yang dapat diselesaikan.');
|
|
}
|
|
|
|
// Update status sewa menjadi selesai hanya untuk sewa terlama
|
|
$oldestSewa->update(['status' => 'selesai']);
|
|
|
|
DB::commit();
|
|
return redirect()->route('paket.index')->with('success', 'Satu unit paket berhasil diaktifkan kembali.');
|
|
} catch (\Exception $e) {
|
|
DB::rollback();
|
|
return redirect()->route('paket.index')->with('error', 'Terjadi kesalahan: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Mengaktifkan semua unit paket yang sedang disewa
|
|
*/
|
|
public function activateAll($id)
|
|
{
|
|
try {
|
|
DB::beginTransaction();
|
|
|
|
$paket = Paket::findOrFail($id);
|
|
|
|
// Update status semua sewa yang masih aktif menjadi selesai
|
|
$count = $paket->sewas()
|
|
->whereIn('status', ['confirmed', 'ongoing'])
|
|
->update(['status' => 'selesai']);
|
|
|
|
if ($count === 0) {
|
|
return redirect()->route('paket.index')->with('error', 'Tidak ada penyewaan aktif yang dapat diselesaikan.');
|
|
}
|
|
|
|
DB::commit();
|
|
return redirect()->route('paket.index')->with('success', 'Semua unit paket berhasil diaktifkan kembali.');
|
|
} catch (\Exception $e) {
|
|
DB::rollback();
|
|
return redirect()->route('paket.index')->with('error', 'Terjadi kesalahan: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Menampilkan detail paket untuk modal
|
|
*/
|
|
public function detail($id)
|
|
{
|
|
try {
|
|
$paket = Paket::findOrFail($id);
|
|
$detailBarang = $paket->detail_barang ?? [];
|
|
$barangs = [];
|
|
foreach ($detailBarang as $barang) {
|
|
$barangs[] = [
|
|
'nama_barang' => $barang['nama_barang'] ?? '',
|
|
'pivot' => [
|
|
'jumlah' => $barang['jumlah'] ?? 0
|
|
]
|
|
];
|
|
}
|
|
return response()->json([
|
|
'id' => $paket->id,
|
|
'nama_paket' => $paket->nama_paket,
|
|
'jenis_paket' => $paket->jenis_paket,
|
|
'harga' => $paket->harga,
|
|
'stok' => $paket->stok,
|
|
'minimum_order' => $paket->minimum_order,
|
|
'keterangan' => $paket->keterangan,
|
|
'image' => $paket->image,
|
|
'barangs' => $barangs
|
|
]);
|
|
} catch (\Exception $e) {
|
|
return response()->json(['error' => 'Paket tidak ditemukan'], 404);
|
|
}
|
|
}
|
|
} |