@extends('layouts.app') @section('title', 'BOM, HPP & Harga') @section('content') @php $formatNumber = fn ($value) => rtrim(rtrim(number_format((float) $value, 2, ',', '.'), '0'), ','); $mapHppItems = function ($items) { return $items->map(function ($item) { $material = $item->material; $baseUnit = $material->baseUnit; $purchaseUnit = $material->purchaseUnit ?: $baseUnit; $factor = (int) $purchaseUnit?->id === (int) $material->base_unit_id ? 1 : (float) ($material->purchase_conversion_factor ?: $purchaseUnit?->conversion_factor ?: 1); return [ 'raw_material_id' => (int) $item->raw_material_id, 'unit_id' => (int) $item->unit_id, 'name' => $material->name, 'purchase_label' => $purchaseUnit && $baseUnit ? '1 '.$purchaseUnit->symbol.' = '.rtrim(rtrim(number_format($factor, 2, '.', ''), '0'), '.').' '.$baseUnit->symbol : '-', 'purchase_price' => (float) $material->average_price * $factor, 'purchase_factor' => $factor, 'purchase_unit' => $purchaseUnit?->symbol ?: $baseUnit?->symbol ?: '-', 'quantity' => (float) $item->quantity, 'unit' => $item->unit?->symbol ?: $baseUnit?->symbol ?: '-', 'unit_cost' => (float) $item->unit_cost, 'line_factor' => (int) $item->unit_id === (int) $material->base_unit_id ? 1 : (float) ($material->purchase_conversion_factor ?: $item->unit?->conversion_factor ?: 1), 'hpp' => (float) $item->total_hpp, ]; })->values(); }; $pricePayload = $products->mapWithKeys(fn ($product) => [$product->id => [ 'type' => $product->type, 'standard_final_price' => (float) $product->final_price, 'hpp_list_total' => (float) ($product->activeHppList?->total_hpp ?? 0), 'hpp_list_items' => $product->activeHppList ? $mapHppItems($product->activeHppList->items) : [], 'prices' => $product->prices->mapWithKeys(fn ($price) => [$price->branch_id => [ 'hpp' => (float) $price->hpp_snapshot, 'margin_type' => $price->margin_type, 'margin_value' => (float) $price->margin_value, 'final_price' => (float) $price->final_price, ]]), ]]); $recipeUnitPayload = $units->map(fn ($unit) => [ 'id' => (int) $unit->id, 'name' => $unit->name, 'symbol' => $unit->symbol, 'base_unit_id' => $unit->base_unit_id === null ? null : (int) $unit->base_unit_id, 'conversion_factor' => $unit->conversion_factor, ]); $recipeMaterialPayload = $materials->map(fn ($material) => [ 'id' => (int) $material->id, 'name' => $material->name, 'base_unit_id' => (int) $material->base_unit_id, 'purchase_unit_id' => $material->purchase_unit_id === null ? null : (int) $material->purchase_unit_id, 'purchase_conversion_factor' => $material->purchase_conversion_factor, 'average_price' => (float) $material->average_price, ]); @endphp
Pengaturan produk

BOM, HPP & Harga Jual

Urutan kerja: harga bahan → resep BOM → harga jual per cabang.

Ringkasan HPP produk

HPP BOM selalu mengikuti resep aktif; transaksi lama tetap memakai snapshot saat transaksi dibuat.

@foreach($products as $product)@endforeach
ProdukJenis stokSumber HPPHPP aktifHarga standar
{{ $product->name }}{{ ['bom'=>'BOM / resep','direct'=>'Stok langsung','non_stock'=>'Non-stok'][$product->type] }}{{ $product->type === 'bom' ? 'Resep BOM aktif' : 'Snapshot stok per cabang' }}Rp{{ number_format($product->activeRecipe?->total_hpp ?? $product->prices->first()?->hpp_snapshot ?? 0,0,',','.') }}Rp{{ number_format($product->final_price,0,',','.') }}

Resep BOM

Pilih menu, lalu atur bahan dan pemakaian per porsi.

Alur: pilih bahan dan tentukan jumlah pemakaian per porsi. Harga jual dan margin diatur di tab Harga jual.

Daftar resep aktif

@forelse($products->where('type','bom') as $product)@empty@endforelse
KategoriProdukVersiIsi resep per porsiAksi
{{ $product->category?->name ?? 'Tanpa kategori' }}{{ $product->name }}{{ $product->activeRecipe?->version ? 'v'.$product->activeRecipe->version : '-' }}@forelse($product->activeRecipe?->items ?? [] as $item){{ $item->material->name }}: {{ $formatNumber($item->quantity) }} {{ $item->unit?->symbol }}@emptyBelum ada resep aktif@endforelse
Belum ada produk berjenis BOM.
Editor resep BOM

Resep

Atur bahan dan jumlah pemakaian per porsi. Harga jual diatur di tab Harga jual.

@csrf
BahanPemakaian 1 porsi

Harga jual per cabang

Tambah atau ubah HPP, margin, dan harga final melalui modal ini.

Pengaturan harga jual

Harga jual per cabang

List HPP per item di bawah ini terpisah dari Resep BOM — potongan stok tetap mengikuti tab Resep BOM, list ini cuma dasar hitung harga jual.

@csrf

Daftar harga semua produk per cabang

Produk BOM tercantum pada kolom Jenis. HPP BOM mengikuti resep aktif; harga diubah melalui tombol Edit.

@if($products->isEmpty()) @else @foreach($products as $product) @foreach($branches as $branch) @php($branchPrice = $product->prices->firstWhere('branch_id', $branch->id)) @endforeach @endforeach @endif
ProdukJenisCabangSumber HPPHPPMarginHarga finalStatusAksi
Belum ada produk.
{{ $product->name }}{{ ['bom' => 'BOM / resep', 'direct' => 'Stok langsung', 'non_stock' => 'Non-stok'][$product->type] ?? $product->type }}{{ $branch->name }}{{ $product->type === 'bom' ? ($product->activeRecipe ? 'Resep BOM aktif' : 'Resep BOM belum ada') : ($branchPrice ? 'Snapshot stok cabang' : 'Belum ada snapshot') }}Rp{{ number_format($product->type === 'bom' ? ($product->activeRecipe?->total_hpp ?? 0) : ($branchPrice?->hpp_snapshot ?? 0), 0, ',', '.') }}{{ $branchPrice ? number_format($branchPrice->margin_value, 2, ',', '.').' % '.$branchPrice->margin_type : '-' }}Rp{{ number_format($branchPrice?->final_price ?? $product->final_price, 0, ',', '.') }}{{ $branchPrice ? 'Harga cabang ditetapkan' : 'Harga standar' }}
@endsection @push('scripts')@endpush