UPDATE v551: Part yang hanya punya NAMA tidak lagi otomatis Waiting Part — dicocokkan ke SOH lewat namanya >>> BACKEND BERUBAH — WAJIB RESTART <<< >>> FRONTEND WAJIB BUILD ULANG <<< >>> TIDAK ADA PERUBAHAN STRUKTUR TABEL <<< BERKAS BERUBAH (2) backend/routes/detailpart.js endpoint baru + perbaikan impor frontend/src/views/MonitoringUnit.vue pencocokan nama + tampilannya CATATAN: paket ini TIDAK memuat v549/v550 (izin bypass Pengecekan Awal). Kedua berkas di sini tidak bersinggungan dengan perubahan itu, jadi urutan pemasangannya bebas. ================================================================ 1. APA YANG SEBENARNYA TERJADI ================================================================ Seluruh pencarian stok berpatokan pada Part Number saja. Di detailpart.js, jalur impor Excel membungkus SELURUH pengecekan gudang dengan `if (pn) { ... }` — baris tanpa Part Number melewatinya, lalu jatuh ke baris ini: const status = stockInfo ? (Stock > 0 ? 'Tersedia' : 'Waiting Part') : 'Waiting Part' `stockInfo` tetap null karena tidak pernah dicari. Jadi "TIDAK DICEK" dan "dicek, ternyata habis" berakhir di tempat yang sama persis. Nama part tidak pernah dilihat, padahal kolomnya ada di ketiga tabel SOH. Di frontend polanya sama: cekStokManual() dan cekStokBanyak() keduanya berhenti di baris pertama bila Part Number kosong. ================================================ 2. AKIBAT YANG TIDAK TERLIHAT DI LAYAR ITU ================================================ Baris tanpa Part Number tidak sekadar tampil "⏳ Waiting". Ia ikut terhitung sebagai part yang menunggu, dan sinkronRekap() di backend lalu: - menarik SELURUH record ke Status_Penggunaan = 'Waiting Part' - membuka segmen 'Waiting Part' di status_durasi_log Segmen itu terus berjalan sampai ada yang menutupnya. Jadi satu baris yang cuma diketik namanya bisa membuat unit tercatat menunggu part berhari-hari — dan angka itu ikut terbawa ke MTTR serta rekap durasi. DAN IA TIDAK DILAPORKAN. Daftar notFound hanya diisi saat `pn` ada, jadi baris tanpa Part Number tidak muncul di ringkasan impor mana pun. Satu-satunya jejaknya adalah status menunggu yang tidak dijelaskan apa pun. ================================================ 3. DUA PERBAIKAN, DAN BATASNYA ================================================ A. NAMA DICOCOKKAN KE SOH Endpoint baru: POST /detail-part/cek-stok-nama cocok PERSIS ke satu Part Number nama sama setelah spasi dirapikan dan huruf disamakan -> Part Number-nya DIISIKAN sendiri, lalu cek stok biasa jalan -> ditandai "✓ diisi dari nama part" di bawah kotaknya selain itu -> TIDAK ditebak. Muncul chip "🔎 N part mirip namanya — pilih". Ditekan, daftarnya terbuka dan orangnya memilih sendiri. tidak ada yang menyerupai -> "🔎 tidak ada yang mirip di SOH MSF 2", status dibiarkan kosong B. YANG TIDAK DICEK DISIMPAN KOSONG, BUKAN 'Waiting Part' Status kosong tidak terhitung menunggu, jadi record-nya tidak tertarik dan durasi waiting tidak berjalan. Part Number yang ADA tapi tidak ketemu di gudang mana pun TETAP 'Waiting Part' seperti sebelumnya — itu memang sudah dicek, dan ia juga sudah dilaporkan lewat daftar notFound. ================================================ 4. KENAPA "COCOK SEBAGIAN YANG HANYA SATU" TETAP HARUS DIPILIH ================================================ Ini keputusan yang paling mudah salah dan paling perlu dijelaskan. Kalau "Hose AC" hanya menyerupai SATU baris SOH, godaannya adalah menerapkannya otomatis — toh tidak ada pilihan lain. Tapi satu-satunya baris itu bisa saja "HOSE AC COMPRESSOR", part yang sama sekali berbeda. Menerapkannya berarti mengisi Part Number yang salah ke permintaan yang akan dikirim ke gudang. Tidak ada yang akan menyadarinya sampai barangnya datang keliru — dan saat itu jejaknya sudah hilang, karena di layar Part Number itu terlihat seperti diketik orang. Jadi aturannya: SATU-SATUNYA KECOCOKAN BUKAN BUKTI KECOCOKAN YANG BENAR. Hanya kesamaan nama PERSIS yang diterapkan sendiri. Sebaliknya, nama yang sama persis tapi menunjuk DUA Part Number berbeda juga masuk "pilih" — itu keadaan nyata di data Anda, dan menebak salah satunya sama buruknya. ================================================ 5. PENCOCOKAN TIDAK MENGHITUNG STOK SENDIRI ================================================ Endpoint /cek-stok-nama hanya menjawab SATU hal: nama ini menunjuk Part Number yang mana. Begitu Part Number-nya diketahui, layar memanggil /cek-stok yang sudah ada. Itu disengaja. Aturan stok memuat hal-hal yang tidak boleh punya salinan kedua: - gudang mana yang dipakai menurut satker unit (PMSE-1 -> MSF 1) - lokasi otomatis - pembedaan "terdaftar tapi habis" dari "belum pernah didaftarkan" (v502) Menyalinnya ke endpoint baru berarti dua tempat yang bisa memberi jawaban berbeda untuk part yang sama. Hal yang sama berlaku di layar: memilih dari daftar hasil pencocokan menuangkannya ke _sohResults — tempat yang SAMA dengan hasil pencarian biasa — sehingga yang dipanggil tetap pilihSoh() yang sudah ada. ================================================ 6. ENAM QUERY, BUKAN SATU PER NAMA ================================================ Tiga query untuk cocok persis (IN ...), tiga untuk cocok sebagian (LIKE ... OR LIKE ...), lalu dicocokkan di memori. Enam total, berapa pun jumlah namanya. Satu query per nama akan tumbuh mengikuti panjang daftar, dan paket PM bisa belasan part. Pencarian sebagian diberi LIMIT 300 per gudang: pola '%kata%' pada tabel SOH yang besar bisa mengembalikan ribuan baris, dan mengirim semuanya ke layar hanya untuk dibuang di sana adalah muatan yang tidak ada gunanya. Nama di bawah 3 huruf dilewati. Dua huruf akan menyerupai ratusan baris, dan daftar pilihan sepanjang itu bukan bantuan. Baris dari tiga gudang DILEBUR per Part Number. Part yang sama ada di MSF 1 dan MSF 2 adalah SATU pilihan, bukan dua — menampilkannya dua kali akan terbaca seperti dua part berbeda dengan nama sama, dan itu justru pertanyaan yang sedang dijawab. Gudang yang sesuai satker unit ditaruh di depan saat harus memilih: pilihan teratas adalah yang paling mungkin ditekan tanpa dibaca. ================================================ 7. GAGAL MENCOCOKKAN TIDAK MEMBUATNYA WAITING ================================================ Kalau permintaan pencocokan gagal, status barisnya dibiarkan apa adanya dan galatnya ditampilkan di baris itu. Itu persis alasan seluruh perubahan ini ada: "tidak tahu" tidak boleh disimpan sebagai "menunggu". ================================================ 8. RINGKASAN IMPOR SEKARANG MENYEBUTNYA ================================================ Muncul bagian baru di notifikasi hasil impor: 🔎 2 baris tanpa Part Number — dicocokkan lewat namanya Baris ini tidak dihitung sebagai Waiting Part, jadi status unit tidak ikut tertarik. Lihat kolom Part Number di tabel... Dipisah dari daftar notFound karena perbaikannya berbeda: notFound sudah punya Part Number dan tinggal didaftarkan ke gudang; yang ini bahkan belum ketahuan menunjuk part yang mana. ================================================ 9. DATA LAMA TIDAK DIUBAH ================================================ Baris yang terlanjur tersimpan sebagai 'Waiting Part' TIDAK dibetulkan otomatis. Membetulkannya berarti menebak mana yang memang menunggu dan mana yang cuma tidak pernah dicek — dan dua-duanya sekarang terlihat sama di database. Baris seperti itu bisa dicari dengan: SELECT rekap_id, Part_Name, Status_Part, Waiting_Start FROM detail_part_rekap WHERE (Part_Number IS NULL OR TRIM(Part_Number) = '') AND LOWER(TRIM(COALESCE(Status_Part,''))) = 'waiting part'; Membuka form record-nya lalu menghapus isi kolom statusnya akan menutup segmen waiting-nya lewat sinkronRekap() seperti biasa. Kalau Anda ingin saya buatkan pembersihan massalnya, bilang saja — tapi itu menyentuh durasi yang sudah tercatat, jadi lebih baik diputuskan tersendiri. ================================================ 10. CARA PASANG ================================================ 1. Extract ke folder yang MEMUAT folder Digitalisasi_3_3, lalu timpa. 2. RESTART BACKEND. 3. cd frontend && npm run build 4. Ctrl+Shift+R di peramban. 5. UJI DENGAN RECORD DI LAYAR ANDA (SE-3004): a. Buka Edit Kebutuhan Sparepart. Baris "Hose AC Split Low" dan "Clamp hose gbagong" TIDAK boleh lagi bertuliskan "⏳ Waiting". b. Yang namanya cocok persis: Part Number-nya terisi sendiri, dengan keterangan "✓ diisi dari nama part" di bawahnya. c. Yang mirip-mirip: muncul chip "🔎 N part mirip namanya — pilih". Tekan, pilih satu, stoknya langsung terisi. d. Yang tidak ada padanannya: "🔎 tidak ada yang mirip", status "— belum dicek". e. Status Penggunaan Unit TIDAK boleh lagi ikut jadi "Waiting Part" hanya karena baris-baris itu. ================================================ YANG SUDAH DIPERIKSA ================================================ - Aturan pencocokan diuji terhadap 7 keadaan, semuanya benar: nama sama persis, 1 PN di 2 gudang -> persis, DITERAPKAN (dua gudang lebur jadi satu pilihan) huruf kecil + spasi ganda -> persis, DITERAPKAN nama sama persis, PN BERBEDA -> pilih, tidak ditebak cocok sebagian, banyak -> pilih cocok sebagian, hanya SATU -> pilih <- lihat bagian 4 tidak ada yang menyerupai -> kosong - Status impor diuji terhadap 4 keadaan: PN ada, stok > 0 -> Tersedia PN ada, stok 0 -> Waiting Part PN ada, tidak ada di gudang mana pun -> Waiting Part (tidak berubah, dan tetap masuk notFound) TANPA PN -> kosong <- yang diperbaiki - Perambatan ke status record diuji: 2 baris netral + 1 Tersedia menghasilkan 0 baris menunggu, jadi record TIDAK tertarik ke Waiting Part — dan baris netral tidak menutupi Waiting yang sungguhan. - detailpart.js lolos `node --check` - 40 berkas .vue lolos @vue/compiler-sfc — 0 bermasalah - `vite build` DIJALANKAN dan BERHASIL (15,2 detik) - Penanda hasil pencocokan diperiksa agar DIBUANG saat orangnya mengetik Part Number sendiri. Kalau tidak, keterangan "diisi dari nama part" akan menempel pada nilai yang sudah diganti tangan — keterangan yang salah lebih buruk daripada tidak ada keterangan. ================================================ YANG BELUM SAYA UJI ================================================ Tidak ada MySQL di tempat saya bekerja. Query pencocokan nama belum pernah dijalankan terhadap tabel SOH sungguhan. DUA HAL YANG PERLU DIPERHATIKAN SAAT LANGKAH 5: KECEPATAN. Pencarian '%kata%' TIDAK bisa memakai indeks — apa pun indeks yang ada di kolom Part_Name. Pada tabel SOH yang besar, query cocok-sebagian akan memindai seluruh tabel. Batas waktunya 20 detik, dan gagal tidak merusak apa pun (bagian 7), tapi kalau chip "🔎 cocokkan nama…" terasa lama, itu sebabnya. Kalau memang lambat, kabari saya — jalan keluarnya ada, tapi berbeda tergantung seberapa besar tabelnya. ISI KOLOM Part_Name di SOH. Seluruh fitur ini bersandar pada nama di SOH ditulis mirip dengan yang diketik orang. Kalau penulisannya jauh berbeda, hasilnya akan banyak "tidak ada yang mirip" — dan itu BUKAN kegagalan program. Bedanya sekarang: baris seperti itu tidak lagi diam-diam jadi Waiting Part.