PT. ROYAL MULTIPACK PLASINDO

Enterprise Management System Solution

Masuk Akses Karyawan

Gunakan ID Karyawan & Password Terdaftar

Belum memiliki akun?

\n `);w.document.close(); }; })(); d.close(); try{this.logAudit('CETAK_BARCODE_SO',`${o.soNumber} • Kode Pabrik ${factoryCode} • ${qty} label 50x20mm`)}catch(_e){} setTimeout(()=>{try{frame.contentWindow.focus();frame.contentWindow.print()}catch(err){console.error(err)}},120); }catch(err){ console.error('printSOBarcodes V9.17',err); this.showToast('Cetak Barcode Gagal',err?.message||String(err),'error'); } }; })(); `);w.document.close();} P.viewPurchasePdf983=function(id){const r=(this.state.purchaseRequests||[]).find(x=>String(x.id)===String(id)),d=pdfOf(r);if(!d)return this.showToast?.('PDF Belum Ada','Permintaan ini belum memiliki PDF.','warning');showData('PDF Pembelian '+id,d,true);r.pdfViewedByAdmin=true;r.pdfViewedAt=new Date().toISOString();this.saveState();}; P.viewReceivingPhoto983=function(id){const r=(this.state.purchaseRequests||[]).find(x=>String(x.id)===String(id)),d=r?.latestReceptionPhoto||r?.receivingProofPhoto;if(!d)return this.showToast?.('Foto Belum Ada','Belum ada foto penerimaan.','warning');showData('Foto Penerimaan '+id,d,false);r.receptionPhotoViewedByAdmin=true;r.receptionPhotoViewedAt=new Date().toISOString();this.saveState();}; // MASTER DATA: exact order Customer -> History -> Global, plus reliable Global add/edit. P.renderMasterDataPro=function(c){this.state.masterItems=Array.isArray(this.state.masterItems)?this.state.masterItems:[];this.state.customerMaster=Array.isArray(this.state.customerMaster)?this.state.customerMaster:[];const hist=[];this.state.customerMaster.forEach(x=>(x.priceHistory||[]).forEach(h=>hist.push({...h,customerCode:x.code,customerName:x.name})));hist.sort((a,b)=>String(b.date||'').localeCompare(String(a.date||''))); c.innerHTML=`${this.pageHead('Master Data','Urutan: Master Customer → Riwayat Perubahan → Master Data Global.',`
`)}
1. MASTER CUSTOMER
${this.state.customerMaster.map((x,i)=>``).join('')||''}
KodeCustomerPPNAlamatProduk & HargaAksi
${E(x.code)}${E(x.name||x.companyName)}${ppnOf(x)?'✓ PPN 11%':'Non PPN'}${E((x.addresses||[]).map(a=>a.address).filter(Boolean).join(' | ')||x.address||'-')}${(x.products||[]).map(p=>`
${E(p.sku)} ${E(p.name)} — Rp ${N(p.price).toLocaleString('id-ID')}
`).join('')||'-'}
Belum ada customer.
2. RIWAYAT PERUBAHAN
${hist.map(h=>``).join('')||''}
WaktuCustomerSKUBarangHarga LamaHarga BaruOleh
${E(h.date||'-')}${E(h.customerCode||'-')} • ${E(h.customerName||'-')}${E(h.sku||'-')}${E(h.name||'-')}Rp ${N(h.oldPrice).toLocaleString('id-ID')}Rp ${N(h.price).toLocaleString('id-ID')}${E(h.by||'-')}
Belum ada perubahan.
3. MASTER DATA GLOBAL
${this.state.masterItems.map((x,i)=>``).join('')||''}
SKU/KodeNama BarangJenisKategoriSatuanAksi
${E(code(x))}${E(x.name)}${E(x.itemType||'-')}${E(x.category||'-')}${E(x.unit||'-')}
Belum ada barang global.
`;}; P.showGlobalItem983=function(i){const x=i==null?{factoryCode:'',name:'',itemType:'BARANG JADI',category:'',unit:'ROLL'}:{...this.state.masterItems[i]};document.getElementById('modalContent').innerHTML=`

${i==null?'Tambah':'Edit'} Barang Global

`;document.getElementById('modalOverlay').classList.remove('hidden');}; P.saveGlobalItem983=function(e,i){e.preventDefault();const cd=document.getElementById('g983code').value.trim(),name=document.getElementById('g983name').value.trim();if(this.state.masterItems.some((x,n)=>n!==i&&U(code(x))===U(cd)))return this.showToast?.('Kode Sudah Ada','Gunakan SKU/kode lain.','error');const old=i>=0?this.state.masterItems[i]:{},obj={...old,factoryCode:cd,code:cd,name,itemType:document.getElementById('g983type').value,category:document.getElementById('g983cat').value.trim(),unit:document.getElementById('g983unit').value,updatedAt:new Date().toISOString()};if(i>=0)this.state.masterItems[i]=obj;else this.state.masterItems.push(obj);this.saveState();this.logAudit?.('MASTER_GLOBAL_SIMPAN',cd+' • '+name);this.closeModal();this.navigateTo('master_data');this.showToast?.('Tersimpan','Barang global berhasil disimpan.','success');}; // PURCHASE ADMIN: one row shows original request PDF and the linked receiving photo. P.renderPurchaseValidationPro=function(c){const rs=(this.state.purchaseRequests||[]).slice().reverse();c.innerHTML=`${this.pageHead('Validasi Pembelian Admin','PDF permintaan dan foto penerimaan tampil pada transaksi pembelian yang sama.')}
${rs.map(r=>{const pdf=pdfOf(r),photo=r.latestReceptionPhoto||r.receivingProofPhoto,final=U(r.status)==='MENUNGGU_VALIDASI_AKHIR_ADMIN',done=U(r.status)==='SELESAI';return ``}).join('')||''}
No. PermintaanBarang PembelianPDF PembelianFoto PenerimaanStatusValidasi
${E(r.id)}
${E(r.date||'-')}
${prItems(r).map(i=>`
${E(i.itemName)}
Diminta ${N(i.qty)} • Diterima ${N(i.receivedQty)} ${E(i.unit)}
`).join('
')}
${pdf?`
${r.pdfViewedByAdmin?'✓ sudah dilihat':'belum dilihat'}
`:'PDF BELUM ADA'}
${photo?`
${r.receptionPhotoViewedByAdmin?'✓ sudah dilihat':'belum dilihat'}
`:'Belum diterima Gudang'}
${E(r.status||'-')}${done?'SELESAI':final?``:``}
Belum ada permintaan pembelian.
`;}; // RECEIVING: strictly linked to approved purchase request above, with PDF visible and camera required. P.renderRawReceivingPro=function(c){const allowed=['DISETUJUI_ADMIN_MENUNGGU_BARANG','DISETUJUI_ADMIN_MENUNGGU_BARANG_DATANG','DITERIMA_SEBAGIAN','PENERIMAAN_SEBAGIAN','MENUNGGU_VALIDASI_AKHIR_ADMIN'];const rs=(this.state.purchaseRequests||[]).filter(r=>allowed.includes(U(r.status))).slice().reverse();c.innerHTML=`${this.pageHead('Penerimaan Barang Pembelian','Penerimaan WAJIB memilih transaksi pembelian yang sudah disetujui Admin. Barang dan qty berasal dari permintaan tersebut.')}
${rs.map(r=>``).join('')||''}
PembelianBarang Sesuai PermintaanPDF AsalSudah DiterimaStatusAksi
${E(r.id)}
${E(r.date||'-')}
${prItems(r).map(i=>`
${E(i.itemName)} — ${N(i.approvedQty||i.qty)} ${E(i.unit)}
`).join('')}
${pdfOf(r)?``:'-'}${prItems(r).map(i=>`
${N(i.receivedQty)} / ${N(i.approvedQty||i.qty)} ${E(i.unit)}
`).join('')}
${E(r.status)}${U(r.status)==='MENUNGGU_VALIDASI_AKHIR_ADMIN'?'Menunggu Validasi Admin':``}
Belum ada pembelian yang sudah disetujui Admin.
`;}; P.showReceiveRawModal983=function(id){const r=(this.state.purchaseRequests||[]).find(x=>String(x.id)===String(id));if(!r)return;const its=prItems(r);document.getElementById('modalContent').innerHTML=`

Penerimaan • ${E(id)}

Barang dikunci mengikuti Permintaan Pembelian yang disetujui Admin.

${pdfOf(r)?``:''}
${its.map((i,n)=>{const max=Math.max(0,N(i.approvedQty||i.qty)-N(i.receivedQty));return ``}).join('')}
Barang PembelianDimintaSudahQty Diterima Sekarang (EDIT)
${E(i.itemName)}${N(i.approvedQty||i.qty)} ${E(i.unit)}${N(i.receivedQty)} ${E(i.unit)}
📷 FOTO BARANG DITERIMA — WAJIB DARI KAMERA

Tekan tombol kamera di bawah. Foto ini tersimpan pada pembelian ${E(id)} dan dapat dibuka Admin.

`;document.getElementById('modalOverlay').classList.remove('hidden');}; P.saveRawReceiving983=async function(e,id){e.preventDefault();const r=(this.state.purchaseRequests||[]).find(x=>String(x.id)===String(id));if(!r)return;const f=document.getElementById('recv983photo')?.files?.[0];if(!f)return this.showToast?.('Foto Wajib','Ambil foto barang dengan kamera.','warning');const toData=file=>new Promise((res,rej)=>{const q=new FileReader();q.onload=()=>res(q.result);q.onerror=rej;q.readAsDataURL(file)});const photo=await toData(f),its=prItems(r),inputs=[...document.querySelectorAll('.recv983qty')];let total=0;inputs.forEach(inp=>{const i=its[N(inp.dataset.i)],q=N(inp.value),max=Math.max(0,N(i.approvedQty||i.qty)-N(i.receivedQty));if(q>max)throw new Error('Qty melebihi sisa '+i.itemName);if(q>0){i.receivedQty=N(i.receivedQty)+q;total+=q;const m=(this.state.rawMaterials||[]).find(x=>String(x.id)===String(i.itemId)||U(x.name)===U(i.itemName));if(m)m.stock=N(m.stock)+q;this.state.warehouseInboundLog=this.state.warehouseInboundLog||[];this.state.warehouseInboundLog.push({id:'BB-IN-'+Date.now()+'-'+Math.random().toString(36).slice(2,5),purchaseRequestId:r.id,purchaseNo:r.id,receiptNo:document.getElementById('recv983no').value.trim(),date:new Date().toISOString().slice(0,10),itemId:i.itemId,itemName:i.itemName,qty:q,unit:i.unit,type:'PENERIMAAN_PEMBELIAN'});}});if(total<=0)return this.showToast?.('Qty Kosong','Isi qty barang yang diterima.','warning');r.items=its;r.latestReceiptNo=document.getElementById('recv983no').value.trim();r.latestReceptionPhoto=photo;r.receivingProofPhoto=photo;r.latestReceptionAt=new Date().toISOString();r.latestReceptionBy=this.state.currentUser?.name||this.state.currentUser?.id||'-';r.receiveNote=document.getElementById('recv983note').value.trim();r.receptionPhotoViewedByAdmin=false;const remain=its.reduce((a,i)=>a+Math.max(0,N(i.approvedQty||i.qty)-N(i.receivedQty)),0);r.status=remain<=0?'MENUNGGU_VALIDASI_AKHIR_ADMIN':'DITERIMA_SEBAGIAN';this.saveState();this.logAudit?.('PENERIMAAN_PEMBELIAN',id+' • foto kamera • '+total);this.closeModal();this.navigateTo('raw_receiving');this.showToast?.('Penerimaan Tersimpan','Foto sudah terhubung ke pembelian '+id+' dan dapat dilihat Admin.','success');}; // Compact production slot inspired by reference; all date click/popup/capacity logic retained. P.renderProductionSlots953=function(c){const now=new Date(),month=this.slotMonth953||`${now.getFullYear()}-${String(now.getMonth()+1).padStart(2,'0')}`,[yy,mm]=month.split('-').map(Number),days=new Date(yy,mm,0).getDate(),first=new Date(yy,mm-1,1).getDay(),names=['Min','Sen','Sel','Rab','Kam','Jum','Sab'];let cells=names.map(x=>`
${x}
`).join('');for(let i=0;i';for(let d=1;d<=days;d++){const date=`${yy}-${String(mm).padStart(2,'0')}-${String(d).padStart(2,'0')}`,s=this.slotStatus953?this.slotStatus953(date):{cap:N(this.state.productionSlotSettings?.dailyTarget)||600,used:0,left:0,full:false};cells+=``}const logo=typeof getRoyalLogoSVG==='function'?getRoyalLogoSVG('76px','62px',false):'
RMP
';c.innerHTML=`
${logo}
SLOT BUBBLE ROYAL MULTIPACK PLASINDO
PT. ROYAL MULTIPACK PLASINDO • CITEUREUP, KAB. BOGOR
BULAN PRODUKSI
${new Date(yy,mm-1,1).toLocaleDateString('id-ID',{month:'long',year:'numeric'}).toUpperCase()}
${cells}
`;}; // Make SO PPN visibly follow Master Customer even if another modal path is used. const oldSO=P.showSOProModal; if(oldSO)P.showSOProModal=function(){oldSO.call(this);setTimeout(()=>{const sel=document.getElementById('msoCust53'),cb=document.getElementById('msoPPN980');if(!sel||!cb)return;const sync=()=>{const cu=(this.state.customerMaster||[]).find(x=>U(x.code)===U(sel.value));cb.checked=ppnOf(cu);cb.disabled=false;const lab=cb.closest('label');if(lab){const b=lab.querySelector('b');if(b)b.textContent='PPN 11% — default dari Master Customer, bisa diubah';}this.calcSO980?.()};sel.addEventListener('change',sync);sync();},0)}; console.log('[RMP V9.83] definitive fixes active'); })();