@extends('layouts/base_view') @section('title') {!! $variables['header_routes'] !!} @endsection @section('content')

Stock Opname

@csrf
{{ auth()->user()->fullname }}
@if(auth()->user()->roles->isNotEmpty()) {{ auth()->user()->roles->pluck('name')->join(', ') }} @endif
@if(session('store_selected')) @php $stores = Cache::get('select_stores', []); $selectedStore = collect($stores)->firstWhere('id', session('store_selected')); @endphp
{{ $selectedStore ? $selectedStore->name : 'No Store Selected' }}
@else
No Store Selected
@endif
@if(isset($data->id) && $data->status) {{ $data->status }} @else Belum Disimpan @endif
@if(auth()->user()->canBackdateSO()) Backdate diizinkan @else Tanggal sistem (tidak bisa backdate) kecuali user tertentu @endif

Rumus Perhitungan SPB

Item DO (Delivery Order)

Pengiriman via DO menangani tipe HARIAN dan PERIODIK.

DO HARIAN:

SPB = (Forecast Besok + Forecast Lusa + TSM Lusa) - LSM Aktual - Open SPB
  • Cek H+2: H+2 (tanpa skip libur) harus jatuh di delivery day
  • Forecast Besok: Forecast H+1 (1 hari setelah SO)
  • Forecast Lusa: Forecast H+2 (2 hari setelah SO)
  • TSM Lusa: TSM H+2 (target sisa malam di hari lusa)
  • LSM Aktual: Ending Stock dari SO hari ini
  • Open SPB: Total SPB yang belum CLOSED

Contoh DO HARIAN:

SO tanggal Jumat 5 Sept 2025:
• Forecast Besok (Sabtu 6 Sept) = 105.25
• Forecast Lusa (Minggu 7 Sept) = 98.75
• TSM Lusa (Minggu 7 Sept) = 50.25
• LSM Aktual = 150.00
SPB = (105.25 + 98.75 + 50.25) - 150.00 = 104.25 Pakai

DO PERIODIK:

SPB = Total Forecast (Coverage) - LSM Aktual - Open SPB
  • H+2 DENGAN LIBUR: Tidak skip hari libur saat cari shipment
  • Coverage Logic: Check delivery day, find next shipment
  • TIDAK skip libur: Semua hari dihitung saat sum forecast
  • TIDAK pakai TSM: Hanya forecast saja
  • Delivery Days: Dari Shipment Deliveries (filter by period_id)

Contoh DO PERIODIK:

SO: Selasa, 13 Jan 2025, Delivery days: ["Senin", "Kamis"]
• H+2 hari kerja = Kamis, 15 Jan (delivery day ✓)
• Next delivery = Senin, 19 Jan
• Coverage = Jumat 16 - Senin 19 Jan (4 hari)
• Total Forecast = 200.50 (termasuk libur!)
• LSM Aktual = 50.00, Open SPB = 10.00
SPB = 200.50 - 50.00 - 10.00 = 140.50 Pakai
* DO PERIODIK: Semua hari dihitung (TIDAK skip libur)

Kesimpulan, Usulan SPB akan muncul apabila :
  • DO HARIAN: cek H+2 dari Shipment Deliveries berdasarkan tipe pengiriman HARIAN.
  • DO PERIODIK: cek H+2 dari Shipment Deliveries berdasarkan tipe pengiriman PERIODIK.
  • PR PERIODIK: cek H+2 HARI KERJA (skip libur) dari Shipment Suppliers berdasarkan item RM.
Catatan : untuk kolom Saran SPB, Hasil perhitungan dalam UOM Pakai akan dikonversi ke UOM Kirim (jika ada). Konversi: Pakai → Utuh → Kirim. Hasil akhir UOM Kirim akan dibulatkan ke angka bulat terdekat.
Item PR (Purchase Request)

Pengiriman via PR hanya menangani tipe PERIODIK, Apabila dikemudian hari menangani tipe HARIAN, maka rumus perlu disesuaikan.

SPB = Total Forecast (Coverage Period) - LSM Aktual - Open SPB

Coverage Period Logic:

  • Shipment Date: H+2 HARI KERJA (skip libur)
  • Check Shift: Jika shipment date BUKAN hari shift → Tidak ada SPB
  • Find Next Shipment: Skip libur (must be shift day AND not holiday)
  • Coverage: Dari hari setelah shipment sampai shipment berikutnya (INCLUSIVE)
  • Sum Forecast: HITUNG SEMUA HARI termasuk libur (hanya skip libur saat cari shipment)
  • Shifts: Dari Shipment Supplier (contoh: ["Senin","Kamis"])

Contoh PR PERIODIK:

Scenario 1 - Normal:
• SO: Selasa, 13 Jan 2026
• Shifts: ["Senin", "Kamis"]
• H+2 hari kerja = Kamis, 15 Jan
• Kamis ADALAH hari shift ✓
• Next Shipment = Senin, 19 Jan
• Coverage = Jumat 16 - Senin 19 Jan (4 hari)
• Total Forecast (16-19 Jan) = 200.50
• LSM Aktual = 50.00, Open SPB = 10.00
SPB = 200.50 - 50.00 - 10.00 = 140.50 Pakai
* Libur hanya di-skip saat cari shipment, tapi tetap dihitung saat sum forecast
Scenario 2 - Next shipment hari libur:
• SO: Rabu, 31 Des 2025
• Shifts: ["Senin", "Kamis"]
• H+2 hari kerja = Senin, 5 Des (skip Sabtu/Minggu)
• Senin ADALAH hari shift ✓
• Next Shipment = Kamis, 1 Jan 2026 (LIBUR!)
• Skip ke next valid shipment = Senin, 5 Jan 2026
• Coverage = Selasa 30 Des - Senin 5 Jan (7 hari)
Forecast: 30 Des, 31 Des, 1 Jan, 2 Jan, 3 Jan, 4 Jan, 5 Jan
Scenario 2.1 - Shipment jatuh pada hari libur:
• SO: Selasa, 30 Des 2025
• Libur: Kamis 1 Jan 2026 → HARI PENGIRIMAN
• Shifts: ["Senin", "Kamis"]
• H+2 hari kerja = Jum'at, 2 Jan (skip 1 hari libur)
• Jum'at bukan hari pengiriman → Tidak Ada SPB
Kasus ini sudah ditangani oleh Scenario 2

Scenario 3 - Ketemu shipment karena hari libur:
• SO: Rabu, 31 Des 2025
• Libur: Kamis 1, Sabtu 17, Minggu 18 Jan
• Shifts: ["Senin", "Kamis"]
• H+2 hari kerja = Senin, 5 Jan (skip 3 hari libur)
• Senin ADALAH hari pengiriman ✓ → Ada SPB
• Tanggal SPB jatuh pada hari Jum'at 2 Januari 2026.
Scenario 3.1 - Replace nilai SPB:
• SO: Kamis, 1 Jan 2026
• Shifts: ["Senin", "Kamis"]
• H+2 hari kerja = Senin, 5 Jan (skip Sabtu/Minggu)
• Senin ADALAH hari pengiriman ✓ → Ada SPB • Tanggal SPB jatuh pada hari Jum'at 2 Januari 2026.
Kasus seperti ini akan replace nilai SPB pada Scenario 3
@if($data->id > 0) @endif
@foreach($variables['raw_materials'] as $index => $rm) @php $existingDetail = null; if(isset($data->details)) { $existingDetail = $data->details->where('raw_material_id', $rm->id)->first(); } // Get conversion data $hasConversion = $rm->conversion_factor_utuh_pakai && $rm->conversion_factor_utuh_pakai > 0; $conversionFactor = $hasConversion ? $rm->conversion_factor_utuh_pakai : 1; $uomUtuh = $rm->uom_utuh ?? $rm->uom; $uomPakai = $rm->uom_pakai ?? $rm->uom; // Get store raw material mapping for SPB suggestions $mapping = $variables['mappings']->get($rm->id); $hasMapping = $mapping && $mapping->is_active; $showSPB = $hasMapping && ($mapping->spb_flag ?? false); @endphp {{-- FSTR Sub-lines: Display FSTR components (WIP items) for this RM --}} @php // Get all FSTR components (WIP items) that belong to this RM // Example: DRY0048 (parent) has WIP0029, WIP0030, WIP0031 (components) // Filter only components with input_lsm_flag = true to show in LSM input $fstrComponents = $rm->components() ->where('delete_flag', 0) ->where('input_lsm_flag', true) ->with('component') ->get() ->filter(function($comp) { return $comp->component !== null; // Remove components with null component }); @endphp @foreach($fstrComponents as $fstrComponent) @php $fstr = $fstrComponent->component; // Changed from parent to component // Skip if component is null (filtered out) if (!$fstr) continue; $componentQtyPerUnit = $fstrComponent->qty; // Check if this FSTR is also a FSTR (has components) $isFSTR = $fstr->components()->where('delete_flag', 0)->exists(); // Get existing FSTR qty_pakai from SO detail if exists $existingFstrQty = 0; if ($existingDetail && $existingDetail->fstr_qty_pakai) { $fstrQtyData = is_string($existingDetail->fstr_qty_pakai) ? json_decode($existingDetail->fstr_qty_pakai, true) : $existingDetail->fstr_qty_pakai; $existingFstrQty = $fstrQtyData[$fstr->id] ?? 0; } @endphp @endforeach @endforeach
No Code Description UOM Pakai Current Stock Sisa Utuh Sisa Pakai LSM Aktual DOI Adjustments Status Stok Tipe Dok Saran Qty Final Qty Action
{{ $index + 1 }} @if(!$hasConversion)
@endif
{{ $rm->code }} @if(!$hasConversion)
Tidak ada mapping @endif
{{ $rm->name }} @if(!$hasConversion)
⚠️ Menggunakan rasio 1:1 (tidak akurat!) @endif
{{ $uomPakai }} @if($hasConversion)
1 {{ $uomUtuh }} = {{ $conversionFactor }} {{ $uomPakai }} @endif
- + -
Tidak Diketahui
Belum Pernah
@if($variables['fstr_parents']->has($rm->id))
@endif
@php $mapping = $variables['mappings']->get($rm->id); $hasInvMatrix = $mapping && $mapping->inv_matrix_flag; $hasRestan = $mapping && $mapping->adj_restan_flag; $hasExtras = $mapping && $mapping->adj_extras_flag; $hasRingkas = $mapping && $mapping->adj_ringkas_flag; $hasSelisih = $mapping && $mapping->adj_selisih_flag; $hasAnyAdjustment = $hasRestan || $hasExtras || $hasRingkas || $hasSelisih; @endphp @if($hasInvMatrix && $hasAnyAdjustment)

Adjustments

@elseif($hasInvMatrix && !$hasAnyAdjustment)
No adjustment columns
enabled for this item
@else
Adjustment not available
for this material
@endif
@if($showSPB) -
Open SPB: 0.00 @else - @endif
@if($showSPB && $mapping->tipe_dokumen) @if($mapping->tipe_dokumen == 'DO') {{ $mapping->period->code }} / {{ $mapping->tipe_dokumen }} @else {{ $rm->tipe_doi }} / {{ $mapping->tipe_dokumen }} @endif @else - @endif @if($showSPB) - @else - @endif @if($showSPB) @else - @endif @if($data->id > 0) @else - @endif
FSTR: {{ $fstr->code }} {{ $fstr->name }} Menggunakan {{ number_format($componentQtyPerUnit, 4) }} {{ $rm->uom_pakai ?? $rm->uom }} per unit {{-- FSTR qty_pakai input --}} Input qty FSTR akan otomatis menambah qty_pakai bahan baku di atas
@if(!isset($data->id) || $data->status == 'Draft') @endif @if(isset($data->id) && $data->id > 0 && $data->status == 'Submitted') @endif Kembali
@endsection