437 lines
24 KiB
PHP
437 lines
24 KiB
PHP
@extends('layouts.app')
|
|
|
|
@section('content')
|
|
<div class="container-fluid px-4">
|
|
<div class="card shadow-sm mt-4">
|
|
<div class="card-header bg-white">
|
|
<h4 class="mb-0"><i class="fas fa-utensils mr-2"></i>Manajemen Produk - {{ $branch }}</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
@if(session('success'))
|
|
<div class="alert alert-success">{{ session('success') }}</div>
|
|
@endif
|
|
@if($errors->any())
|
|
<div class="alert alert-danger">{{ $errors->first() }}</div>
|
|
@endif
|
|
|
|
<!-- Tabs -->
|
|
<ul class="nav nav-tabs mb-4 font-weight-bold" id="produkTab" role="tablist">
|
|
<li class="nav-item">
|
|
<a class="nav-link active" id="produk-tab" data-toggle="tab" href="#produk" role="tab"><i class="fas fa-boxes mr-2"></i>Daftar Produk</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" id="bahan-baku-tab" data-toggle="tab" href="#bahan-baku" role="tab"><i class="fas fa-leaf mr-2"></i>Manajemen Bahan Baku</a>
|
|
</li>
|
|
</ul>
|
|
|
|
<div class="tab-content" id="produkTabContent">
|
|
<!-- Produk Tab -->
|
|
<div class="tab-pane fade show active" id="produk" role="tabpanel">
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<h5 class="mb-0 font-weight-bold">Daftar Produk - {{ $branch }}</h5>
|
|
<button class="btn btn-primary" onclick="showAddProductModal()">
|
|
<i class="fas fa-plus mr-1"></i> Tambah Produk
|
|
</button>
|
|
</div>
|
|
<div class="table-responsive">
|
|
<table class="table table-bordered table-hover">
|
|
<thead class="thead-light">
|
|
<tr>
|
|
<th>Gambar</th>
|
|
<th>Nama</th>
|
|
<th>Kategori</th>
|
|
<th>Harga Jual</th>
|
|
<th>Stok ({{ $branch }})</th>
|
|
<th>Aksi</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach($products as $p)
|
|
@php $s = $p->stocks->first(); @endphp
|
|
<tr>
|
|
<td style="width:80px;"><img src="{{ $p->image ?? '/images/img/placeholder.png' }}" alt="" style="height:50px;object-fit:cover;border-radius:6px;"></td>
|
|
<td>{{ $p->name }}</td>
|
|
<td>{{ ucfirst($p->category) }}</td>
|
|
<td>Rp {{ number_format($p->selling_price ?? 0,0,',','.') }}</td>
|
|
<td>{{ $s->quantity ?? 0 }} {{ $s->unit ?? '' }}</td>
|
|
<td style="width:150px;">
|
|
<div class="d-flex gap-2">
|
|
<button type="button" class="btn btn-sm btn-warning edit-product-btn"
|
|
data-id="{{ $p->id }}"
|
|
data-name="{{ $p->name }}"
|
|
data-category="{{ $p->category }}"
|
|
data-purchase_price="{{ $p->purchase_price ?? 0 }}"
|
|
data-selling_price="{{ $p->selling_price ?? 0 }}"
|
|
data-recipes='@json($p->recipes->map(function($r){ return ["raw_material_id" => $r->raw_material_id, "quantity_needed" => $r->quantity_needed]; }))'>
|
|
<i class="fas fa-edit"></i>
|
|
</button>
|
|
<form action="/produk/{{ $p->id }}" method="POST" style="display: inline;">
|
|
@csrf
|
|
@method('DELETE')
|
|
<button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('Yakin ingin menghapus produk ini?')">
|
|
<i class="fas fa-trash"></i>
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Bahan Baku Tab -->
|
|
<div class="tab-pane fade" id="bahan-baku" role="tabpanel">
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<h5 class="mb-0 font-weight-bold"><i class="fas fa-boxes text-warning mr-2"></i>Daftar Bahan Baku & Stok Saat Ini</h5>
|
|
<small class="text-muted"><i class="fas fa-info-circle mr-1"></i>Bahan baku otomatis ditambahkan saat mencatat pembelian di Laporan Pembelian</small>
|
|
</div>
|
|
|
|
<div class="card mb-4">
|
|
<div class="card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover align-middle mb-0">
|
|
<thead class="bg-light">
|
|
<tr>
|
|
<th width="70" class="text-center">#</th>
|
|
<th>Nama Bahan Baku</th>
|
|
<th width="150" class="text-center">Satuan</th>
|
|
<th width="150" class="text-right">Total Stok</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach($rawMaterials as $rm)
|
|
<tr>
|
|
<td class="text-center text-muted font-weight-bold">{{ $loop->iteration }}</td>
|
|
<td class="font-weight-bold">{{ $rm->name }}</td>
|
|
<td class="text-center"><span class="badge badge-secondary px-3 py-2">{{ $rm->unit }}</span></td>
|
|
<td class="text-right font-weight-bold" style="color: #ff5e00;">
|
|
{{ number_format($rm->stock_quantity, 0, ',', '.') }} {{ $rm->unit }}
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
@if($rawMaterials->isEmpty())
|
|
<tr>
|
|
<td colspan="4" class="text-center py-4 text-muted">Belum ada bahan baku yang terdaftar.</td>
|
|
</tr>
|
|
@endif
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Add Product Modal -->
|
|
<div class="modal fade" id="addProductModal" tabindex="-1" role="dialog" aria-hidden="true">
|
|
<div class="modal-dialog modal-lg" role="document">
|
|
<div class="modal-content custom-card">
|
|
<div class="modal-header text-white" style="background: linear-gradient(90deg, #ff8a00 0%, #ff5e00 100%); border: none;">
|
|
<h5 class="modal-title font-weight-bold" id="addProductModalLabel">
|
|
<i class="fas fa-plus-circle mr-2"></i> Tambah Produk Baru
|
|
</h5>
|
|
<button type="button" class="close text-white" data-dismiss="modal" aria-label="Close">
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
</div>
|
|
<form action="/produk" method="POST" enctype="multipart/form-data">
|
|
@csrf
|
|
<div class="modal-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label for="name">🏷️ Nama Produk</label>
|
|
<input type="text" class="form-control" id="name" name="name" required placeholder="Masukkan nama produk">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label for="category">📋 Kategori</label>
|
|
<select class="form-control" id="category" name="category" required>
|
|
<option value="">Pilih Kategori</option>
|
|
<option value="makanan">🍛 Makanan</option>
|
|
<option value="minuman">☕ Minuman</option>
|
|
<option value="snack">🍿 Snack</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label for="purchase_price">💰 Harga Beli</label>
|
|
<input type="number" class="form-control" id="purchase_price" name="purchase_price" required placeholder="Masukkan harga beli">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label for="selling_price">💵 Harga Jual</label>
|
|
<input type="number" class="form-control" id="selling_price" name="selling_price" required placeholder="Masukkan harga jual">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="image">📷 Gambar Produk</label>
|
|
<input type="file" class="form-control-file" id="image" name="image" accept="image/*">
|
|
<small class="form-text text-muted">Format: JPEG, PNG, JPG, GIF, SVG (Max: 2MB)</small>
|
|
</div>
|
|
|
|
<hr>
|
|
<h6 class="font-weight-bold"><i class="fas fa-list-alt text-warning mr-2"></i>Resep / Bill of Materials (Opsional)</h6>
|
|
<small class="text-muted d-block mb-2">Tambahkan bahan baku yang dibutuhkan untuk 1 porsi produk ini. Kosongkan jika produk ini tidak membutuhkan bahan baku.</small>
|
|
<div id="recipe-container">
|
|
<div class="recipe-row row align-items-end mb-2">
|
|
<div class="col-md-6">
|
|
<div class="form-group mb-0">
|
|
<label class="small">Bahan Baku</label>
|
|
<select class="form-control form-control-sm" name="recipes[0][raw_material_id]">
|
|
<option value="">-- Pilih Bahan Baku --</option>
|
|
@foreach($rawMaterials as $rm)
|
|
<option value="{{ $rm->id }}">{{ $rm->name }} ({{ $rm->unit }})</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-group mb-0">
|
|
<label class="small">Jumlah Dibutuhkan</label>
|
|
<input type="text" class="form-control form-control-sm" name="recipes[0][quantity_needed]" placeholder="Contoh: 300, 0.5, 300 ml">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<button type="button" class="btn btn-sm btn-danger btn-block" onclick="this.closest('.recipe-row').remove()"><i class="fas fa-trash"></i></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<button type="button" class="btn btn-sm btn-outline-primary mt-2" onclick="addRecipeRow('recipe-container')">
|
|
<i class="fas fa-plus"></i> Tambah Bahan Baku
|
|
</button>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
|
|
<button type="submit" class="btn btn-primary">Simpan Produk</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Edit Product Modal -->
|
|
<div class="modal fade" id="editProductModal" tabindex="-1" role="dialog" aria-hidden="true">
|
|
<div class="modal-dialog modal-lg" role="document">
|
|
<div class="modal-content custom-card">
|
|
<div class="modal-header text-white" style="background: linear-gradient(90deg, #ff8a00 0%, #ff5e00 100%); border: none;">
|
|
<h5 class="modal-title font-weight-bold" id="editProductModalLabel">
|
|
<i class="fas fa-edit mr-2"></i> Edit Produk
|
|
</h5>
|
|
<button type="button" class="close text-white" data-dismiss="modal" aria-label="Close">
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
</div>
|
|
<form action="/produk" method="POST" enctype="multipart/form-data" id="editProductForm">
|
|
@csrf
|
|
@method('PUT')
|
|
<input type="hidden" id="editProductId" name="product_id">
|
|
<div class="modal-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label for="editName">🏷️ Nama Produk</label>
|
|
<input type="text" class="form-control" id="editName" name="name" required>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label for="editCategory">📋 Kategori</label>
|
|
<select class="form-control" id="editCategory" name="category" required>
|
|
<option value="">Pilih Kategori</option>
|
|
<option value="makanan">🍛 Makanan</option>
|
|
<option value="minuman">☕ Minuman</option>
|
|
<option value="snack">🍿 Snack</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label for="editPurchasePrice">💰 Harga Beli</label>
|
|
<input type="number" class="form-control" id="editPurchasePrice" name="purchase_price" required>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label for="editSellingPrice">💵 Harga Jual</label>
|
|
<input type="number" class="form-control" id="editSellingPrice" name="selling_price" required>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="editImage">📷 Gambar Produk</label>
|
|
<input type="file" class="form-control-file" id="editImage" name="image" accept="image/*">
|
|
<small class="form-text text-muted">Format: JPEG, PNG, JPG, GIF, SVG (Max: 2MB)</small>
|
|
</div>
|
|
|
|
<hr>
|
|
<h6 class="font-weight-bold"><i class="fas fa-list-alt text-warning mr-2"></i>Resep / Bill of Materials (Opsional)</h6>
|
|
<small class="text-muted d-block mb-2">Tambahkan bahan baku yang dibutuhkan untuk 1 porsi produk ini. Kosongkan jika produk ini tidak membutuhkan bahan baku.</small>
|
|
<div id="edit-recipe-container">
|
|
<div class="recipe-row row align-items-end mb-2">
|
|
<div class="col-md-6">
|
|
<div class="form-group mb-0">
|
|
<label class="small">Bahan Baku</label>
|
|
<select class="form-control form-control-sm" name="recipes[0][raw_material_id]">
|
|
<option value="">-- Pilih Bahan Baku --</option>
|
|
@foreach($rawMaterials as $rm)
|
|
<option value="{{ $rm->id }}">{{ $rm->name }} ({{ $rm->unit }})</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-group mb-0">
|
|
<label class="small">Jumlah Dibutuhkan</label>
|
|
<input type="text" class="form-control form-control-sm" name="recipes[0][quantity_needed]" placeholder="Contoh: 300, 0.5, 300 ml">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<button type="button" class="btn btn-sm btn-danger btn-block" onclick="this.closest('.recipe-row').remove()"><i class="fas fa-trash"></i></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<button type="button" class="btn btn-sm btn-outline-primary mt-2" onclick="addRecipeRow('edit-recipe-container')">
|
|
<i class="fas fa-plus"></i> Tambah Bahan Baku
|
|
</button>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Batal</button>
|
|
<button type="submit" class="btn btn-primary">Simpan Perubahan</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@push('scripts')
|
|
<script>
|
|
function showAddProductModal() {
|
|
$('#addProductModal').modal('show');
|
|
}
|
|
|
|
function editProduct(id, name, category, purchasePrice, sellingPrice) {
|
|
$('#editProductId').val(id);
|
|
$('#editName').val(name);
|
|
$('#editCategory').val(category);
|
|
$('#editPurchasePrice').val(purchasePrice);
|
|
$('#editSellingPrice').val(sellingPrice);
|
|
$('#editProductForm').attr('action', '/produk/' + id);
|
|
}
|
|
|
|
function addRecipeRow(containerId) {
|
|
var container = document.getElementById(containerId);
|
|
var rowCount = container.querySelectorAll('.recipe-row').length;
|
|
var newRow = document.createElement('div');
|
|
newRow.className = 'recipe-row row align-items-end mb-2';
|
|
newRow.innerHTML = `
|
|
<div class="col-md-6">
|
|
<div class="form-group mb-0">
|
|
<label class="small">Bahan Baku</label>
|
|
<select class="form-control form-control-sm" name="recipes[${rowCount}][raw_material_id]">
|
|
<option value="">-- Pilih Bahan Baku --</option>
|
|
@foreach($rawMaterials as $rm)
|
|
<option value="{{ $rm->id }}">{{ $rm->name }} ({{ $rm->unit }})</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-group mb-0">
|
|
<label class="small">Jumlah Dibutuhkan</label>
|
|
<input type="number" class="form-control form-control-sm" name="recipes[${rowCount}][quantity_needed]" step="any" min="0" placeholder="0">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<button type="button" class="btn btn-sm btn-danger btn-block" onclick="this.closest('.recipe-row').remove()"><i class="fas fa-trash"></i></button>
|
|
</div>
|
|
`;
|
|
container.appendChild(newRow);
|
|
}
|
|
|
|
function populateEditRecipeRows(recipes) {
|
|
var container = document.getElementById('edit-recipe-container');
|
|
container.innerHTML = '';
|
|
|
|
if (!recipes || recipes.length === 0) {
|
|
addRecipeRow('edit-recipe-container');
|
|
return;
|
|
}
|
|
|
|
recipes.forEach(function(r){
|
|
var rowCount = container.querySelectorAll('.recipe-row').length;
|
|
var newRow = document.createElement('div');
|
|
newRow.className = 'recipe-row row align-items-end mb-2';
|
|
newRow.innerHTML = `
|
|
<div class="col-md-6">
|
|
<div class="form-group mb-0">
|
|
<label class="small">Bahan Baku</label>
|
|
<select class="form-control form-control-sm" name="recipes[${rowCount}][raw_material_id]">
|
|
<option value="">-- Pilih Bahan Baku --</option>
|
|
@foreach($rawMaterials as $rm)
|
|
<option value="{{ $rm->id }}">{{ $rm->name }} ({{ $rm->unit }})</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-group mb-0">
|
|
<label class="small">Jumlah Dibutuhkan</label>
|
|
<input type="number" class="form-control form-control-sm" name="recipes[${rowCount}][quantity_needed]" step="any" min="0" placeholder="0">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<button type="button" class="btn btn-sm btn-danger btn-block" onclick="this.closest('.recipe-row').remove()"><i class="fas fa-trash"></i></button>
|
|
</div>
|
|
`;
|
|
container.appendChild(newRow);
|
|
|
|
var select = container.querySelectorAll('select[name="recipes[' + rowCount + '][raw_material_id]"]')[0];
|
|
if (select) select.value = r.raw_material_id;
|
|
var input = container.querySelectorAll('input[name="recipes[' + rowCount + '][quantity_needed]"]')[0];
|
|
if (input) input.value = r.quantity_needed;
|
|
});
|
|
}
|
|
|
|
$(document).ready(function() {
|
|
$(document).on('click', '.edit-product-btn', function(){
|
|
var btn = $(this);
|
|
var id = btn.data('id');
|
|
var name = btn.data('name');
|
|
var category = btn.data('category');
|
|
var purchasePrice = btn.data('purchase_price');
|
|
var sellingPrice = btn.data('selling_price');
|
|
var recipes = btn.data('recipes');
|
|
|
|
if (typeof recipes === 'string') {
|
|
try {
|
|
recipes = JSON.parse(recipes);
|
|
} catch (e) {
|
|
recipes = [];
|
|
}
|
|
}
|
|
|
|
recipes = recipes || [];
|
|
|
|
editProduct(id, name, category, purchasePrice, sellingPrice);
|
|
populateEditRecipeRows(recipes);
|
|
$('#editProductModal').modal('show');
|
|
});
|
|
});
|
|
</script>
|
|
@endpush
|
|
@endsection
|