@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
Urutan kerja: harga bahan → resep BOM → harga jual per cabang.
HPP BOM selalu mengikuti resep aktif; transaksi lama tetap memakai snapshot saat transaksi dibuat.
| Produk | Jenis stok | Sumber HPP | HPP aktif | Harga 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,',','.') }} |
Pilih menu, lalu atur bahan dan pemakaian per porsi.
| Kategori | Produk | Versi | Isi resep per porsi | Aksi |
|---|---|---|---|---|
| {{ $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. | ||||
Tambah atau ubah HPP, margin, dan harga final melalui modal ini.
Produk BOM tercantum pada kolom Jenis. HPP BOM mengikuti resep aktif; harga diubah melalui tombol Edit.
| Produk | Jenis | Cabang | Sumber HPP | HPP | Margin | Harga final | Status | Aksi |
|---|---|---|---|---|---|---|---|---|
| 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' }} | |