Sentidos ERP

Sentidos ERP V240 — Firebase Online Sync enabled.
Sentidos — Inventory
🌐 Sentidos ERP Online Status: Local / Offline
Total Items0
Total Sales₹0.00
Total Purchase₹0.00
ADR Raw Material Stock0 KG
Vendor Raw Material Stock0 KG
Finished Goods0 PCS
Low Stock0
Dashboardનું Raw Material Stock માત્ર Company Stock બતાવે છે. Vendor પાસે issue થયેલો balance Dashboard Stockમાં ગણાશે નહીં.

Raw Material Master

આ જ Raw Material stockનું main source છે. અહીં Add/Purchase કરેલા materialમાંથી Purchase, Vendor Job Work Issue અને Vendor Consumption બધું deduct/add થશે.

Material NameTotal StockAction

Company Raw Material Inward / Stock Add

ઉપરની listમાં માત્ર Material Name અને Total Stock દેખાશે. નીચેની Inward listમાં દરેક batchનો Rate અલગ દેખાશે.



Company Raw Material Inward Entries

DateInward No.SupplierMaterialQtyRateTaxableGST %GSTTotalUnitAction

Item / Material Master


CodeNameCategoryUnitWeight gStockAction

Multi-Component BOM

Unit મહત્વનું છે: Item Masterમાં Raw Material KG હોય અને BOMમાં quantity gram હોય તો software gram→KG automatic convert કરશે.

Product/Component/Materialનું નામ type કરતાં નીચે આખું Name + Code suggestion દેખાશે; suggestion પસંદ કરતાં આખું Product/Component Name fieldમાં રહેશે.

Component / Material CodeQtyUnitAction


ProductComponentQtyUnitAction

🛒 Purchase


એક જ Supplier અને એક જ Bill/Invoiceમાં ઘણી Items હોય તો દરેક Item Add Item કરો અને અંતે એક વખત Save Purchase કરો.
ItemQtyUnitRateTaxableGST %GSTTotalAction
No items added

📋 Purchase Entries

DateSupplierItemQtyUnitRateTaxableGST %GSTTotalInvoice / RefAction
No purchase entries

📊 Purchase Report

DateSupplierItemQtyUnitRateAmountInvoice / Ref
Click Generate Report
Total0.000₹0.00

🏢 Supplier Master

Supplier પાસેથી આવતા O Ring, Packaging Material, Plastic Bag વગેરે માટે Supplier + Item + Rate set કરો.

SupplierItemRateAction

📊 Dispatch Report

Bill No.DateCustomerFinished GoodQtyRateTotal AmountRemark
Click Generate Report
Total0.000₹0.00

👤 Customer Master



CodeCustomer NameAction

Production

Finish Productનું નામ type કરો. નીચે BOM Masterમાં બનાવેલા Product namesમાંથી suggestion આવશે.

Material/component quantities defined in BOM will be deducted automatically.

💰 Finished Goods Rate Master

Finished Goods Item Masterમાંથી પસંદ કરો. અહીંનો Rate Dispatchમાં Finished Good select કરતાં automatic આવશે.



Finished GoodCodeRateAction

🧾 Raw Material Sale / Invoice

Customerને Raw Material વેચવા માટે અહીં Invoice બનાવો. એક જ Invoiceમાં ઘણી Raw Material items ઉમેરી શકાય છે.


Raw MaterialQtyUnitRateTaxableGSTGrand TotalAction
Taxable: ₹0.00   GST: ₹0.00   Grand Total: ₹0.00


📋 Raw Material Sale Invoices

DateInvoice No.CustomerRaw MaterialQtyRateTaxableGSTGrand TotalAction
Total0.000₹0.00₹0.00₹0.00

🚚 Dispatch


Finished GoodQtyUnitRateTaxableGSTGrand TotalAction
Taxable: ₹0.00   GST: ₹0.00   Grand Total: ₹0.00


📋 Dispatch Entries

DateBill No.CustomerFinished GoodQtyRateTaxable AmountGST %TaxGrand TotalRemarkAction

Vendor Master

Job Work Vendor Master. અહીં Vendor add, suggestion અને delete functionality રહેશે.


VendorAction

Vendor Job Work / Subcontracting

Vendor Master → Raw Material Issue → Component Receive. Componentનું weight Item Masterમાંથી automatic આવશે.


🧱 Raw Material Issue to Vendor

Challan No. software automatic generate કરશે.


📋 Last Transaction History — Raw Material Issue to Vendor

No transactions yet.

🔩 Component Receive from Vendor

Receive Challan No. software automatic generate કરશે.

Raw Material Consumption = Component Weight × Receive Qty. Vendor પાસે issue થયેલા Raw Materialમાંથી આ quantity automatic deduct થશે.


Vendor Raw Material Balance

VendorRaw MaterialQty at VendorUnit

Job Work Rate Master

Vendor + Component પ્રમાણે rate એકવાર save કરો. પછી Job Work Receive વખતે rate automatic આવશે.


VendorComponentRate / PCSAction

💰 Accounting


📊 Customer Account Summary

Total Sales (Grand Total)
₹0.00
Total Tax
₹0.00
Payment Received
₹0.00
Due / Outstanding
₹0.00

📚 Combined Party Ledger (Customer + Supplier + Job Work Vendor)

PartySales ReceivablePurchase PayableJob Work PayablePayment ReceivedPayment GivenNet Balance
📄

Reports Dashboard

Select a report from the menu or use the quick buttons below.

🧾

GST Report

View GST summary and details

🚚

Despatch Report

View sales / despatch details

🛒

Purchase Report

View purchase inward details

🏭

Production Report

View production details

👥

Job Work Report

View job work transactions

🚚 Dispatch Report

Bill No.DateCustomerFinished GoodQtyRateTotal AmountRemark
Click Generate Dispatch Report
Total0.000₹0.00

🧾 Purchase Report

DateSupplierItemQtyUnitRateAmountInvoice / Ref
Generate report
Total0.000₹0.00

🏭 Production Report

DateChallan / RefFinished ProductQtyUnit
Generate report
Total Production: 0.000 PCS

Job Work Monthly Report

VendorPart / ComponentQty ReceivedRateJob Work AmountRaw Material Consumed (KG)
Total0₹0.000.000 KG

Stock & Transaction History

CodeNameCategoryUnitWeight gStockAction

DateTypeRefItemQtyAction
`);w.document.close(); } function saveRawSaleInvoice(){ const date=$('rawSaleDate').value||new Date().toISOString().slice(0,10),customer=$('rawSaleCustomer').value.trim(),remark=$('rawSaleRemark').value.trim(); if(!customer)return alert('Customer Name નાખો.'); if(!rawSaleCart.length)return alert('ઓછામાં ઓછી 1 Raw Material item Add કરો.'); const invoiceNo=getNextRawSaleInvoiceNo(),rows=[]; for(const x of rawSaleCart){ const r=rawMaterials.find(y=>String(y.code)===String(x.code));if(!r||x.qty>Number(r.stock||0)+0.000001)return alert('Stock changed. '+x.name+' માટે available stock ઓછો છે.'); const layer=consumeRawMaterialFIFO(x.code,x.qty);if(layer.remaining>0.000001)return alert('Stock insufficient for '+x.name); const amount=x.qty*x.rate,tax=amount*x.taxRate/100,grandTotal=amount+tax; r.stock-=x.qty;r.rate=getRawAverageRate(x.code); addTxn('RAW MATERIAL SALE', '', 'RM:'+x.code, -x.qty, x.unit); const t=transactions[transactions.length-1];t.date=date;t.invoiceNo=invoiceNo;t.customer=customer;t.saleRate=x.rate;t.amount=amount;t.taxRate=x.taxRate;t.tax=tax;t.grandTotal=grandTotal;t.remark=remark;t.itemName=x.name;t.costLayers=layer.layers||[]; rows.push({name:x.name,qty:x.qty,unit:x.unit,rate:x.rate,amount,tax,grandTotal}); } save();rawSaleLastInvoiceRows=rows;$('rawSaleInvoiceNo').value=invoiceNo; $('rawSalePrint').disabled=false;renderRawSaleEntries();msg('rawSaleMsg','Raw Material Invoice saved. Invoice No. '+invoiceNo); rawSaleCart=[];renderRawSaleCart();$('rawSaleMaterial').value='';$('rawSaleCustomer').value='';$('rawSaleRemark').value='';$('rawSaleDate').value=new Date().toISOString().slice(0,10);showNextRawSaleInvoiceNo(); } function showNextRawSaleInvoiceNo(){if($('rawSaleInvoiceNo'))$('rawSaleInvoiceNo').value=getNextRawSaleInvoiceNo();} function renderRawSaleEntries(){ const body=$('rawSaleTable')?.querySelector('tbody');if(!body)return; const rows=(transactions||[]).filter(t=>String(t.type||'').toUpperCase()==='RAW MATERIAL SALE').slice().reverse(); const html=rows.map((t,n)=>{const q=Math.abs(Number(t.qty)||0),r=Number(t.saleRate||0),a=Number(t.amount??q*r),tax=Number(t.tax??0),g=Number(t.grandTotal??a+tax);return `${t.date||''}${t.invoiceNo||''}${t.customer||''}${t.itemName||String(t.item||'').replace(/^RM:/,'')}${q.toFixed(3)}₹${r.toFixed(2)}₹${a.toFixed(2)}₹${tax.toFixed(2)}₹${g.toFixed(2)} `}).join(''); const tq=rows.reduce((v,t)=>v+Math.abs(Number(t.qty)||0),0),ta=rows.reduce((v,t)=>v+Number(t.amount??(Math.abs(Number(t.qty)||0)*Number(t.saleRate||0))),0),tt=rows.reduce((v,t)=>v+Number(t.tax??0),0),tg=rows.reduce((v,t)=>v+Number(t.grandTotal??((Number(t.amount)||0)+(Number(t.tax)||0))),0); body.innerHTML=html||'No raw material sale invoices'; const set=(id,val)=>{const el=$(id);if(el)el.textContent=val;}; set('rawSaleListTotalQty',tq.toFixed(3));set('rawSaleListTotalTaxable','₹'+ta.toFixed(2));set('rawSaleListTotalGst','₹'+tt.toFixed(2));set('rawSaleListTotalGrand','₹'+tg.toFixed(2)); document.querySelectorAll('[data-rs-entry-edit]').forEach(b=>b.onclick=()=>editRawSaleTransaction(b.dataset.rsEntryEdit)); document.querySelectorAll('[data-rs-entry-del]').forEach(b=>b.onclick=()=>deleteRawSaleTransaction(b.dataset.rsEntryDel)); } function editRawSaleTransaction(id){ const t=(transactions||[]).find((x,n)=>String(x.id||n)===String(id));if(!t)return; const oldCode=String(t.item||'').replace(/^RM:/,''), oldQty=Math.abs(Number(t.qty)||0); const newDate=prompt('Sale Date (YYYY-MM-DD):',t.date||new Date().toISOString().slice(0,10));if(newDate===null)return; const newCustomer=prompt('Customer Name:',t.customer||'');if(newCustomer===null)return; const currentName=t.itemName||String(t.item||'').replace(/^RM:/,''); const materialInput=prompt('Raw Material Name / Code:',currentName);if(materialInput===null)return; const materialText=String(materialInput).trim(); const rm=rawMaterials.find(x=>String(x.code).toLowerCase()===materialText.toLowerCase()||String(x.name).toLowerCase()===materialText.toLowerCase()); if(!rm)return alert('Raw Material not found in Master.'); const newQty=Number(prompt('Quantity:',oldQty));if(!Number.isFinite(newQty)||newQty<=0)return alert('Valid Quantity નાખો.'); const newRate=Number(prompt('Sale Rate / KG:',Number(t.saleRate||0)));if(!Number.isFinite(newRate)||newRate<0)return alert('Valid Sale Rate નાખો.'); const newTaxRate=Number(prompt('GST %:',Number(t.taxRate||0)));if(!Number.isFinite(newTaxRate)||newTaxRate<0)return alert('Valid GST નાખો.'); const newRemark=prompt('Remark (Optional):',t.remark||'');if(newRemark===null)return; // Reverse old sale first so the old quantity is available for the edited transaction. const oldRm=rawMaterials.find(x=>String(x.code)===oldCode); if(oldRm){oldRm.stock+=oldQty;const lots=ensureRawLots(oldCode);const layers=Array.isArray(t.costLayers)?t.costLayers:[];if(layers.length)layers.slice().reverse().forEach(l=>lots.unshift({qty:Number(l.qty)||0,rate:Number(l.rate)||0,date:l.date||new Date().toISOString()}));else lots.push({qty:oldQty,rate:Number(t.saleRate||oldRm.rate||0),date:new Date().toISOString()});oldRm.rate=getRawAverageRate(oldCode);} if(newQty>Number(rm.stock||0)+0.000001){ // restore rollback on validation failure if(oldRm){oldRm.stock-=oldQty;const lots=ensureRawLots(oldCode);if(Array.isArray(t.costLayers)&&t.costLayers.length){let left=oldQty;for(let i=lots.length-1;i>=0&&left>0;i--){const take=Math.min(Number(lots[i].qty)||0,left);lots[i].qty-=take;left-=take;if(lots[i].qty<=0.000001)lots.splice(i,1);}}else{let left=oldQty;for(let i=lots.length-1;i>=0&&left>0;i--){const take=Math.min(Number(lots[i].qty)||0,left);lots[i].qty-=take;left-=take;if(lots[i].qty<=0.000001)lots.splice(i,1);}}oldRm.rate=getRawAverageRate(oldCode);} return alert('Stock insufficient for '+rm.name); } const layer=consumeRawMaterialFIFO(String(rm.code),newQty);if(layer.remaining>0.000001)return alert('Stock insufficient for '+rm.name); rm.stock-=newQty;rm.rate=getRawAverageRate(String(rm.code)); t.date=newDate.trim();t.customer=newCustomer.trim();t.item='RM:'+rm.code;t.itemName=rm.name;t.qty=-newQty;t.unit=rm.unit||'KG';t.saleRate=newRate;t.amount=newQty*newRate;t.taxRate=newTaxRate;t.tax=t.amount*newTaxRate/100;t.grandTotal=t.amount+t.tax;t.remark=newRemark;t.costLayers=layer.layers||[]; save();renderRawSaleEntries();msg('rawSaleMsg','Raw Material Sale entry updated successfully.'); } function deleteRawSaleTransaction(id){ const t=(transactions||[]).find((x,n)=>String(x.id||n)===String(id));if(!t)return;if(!confirm('Delete Raw Material Invoice and reverse stock?'))return; const code=String(t.item||'').replace(/^RM:/,''),r=rawMaterials.find(x=>String(x.code)===code),layers=Array.isArray(t.costLayers)?t.costLayers:[]; if(r){r.stock+=Math.abs(Number(t.qty)||0);const lots=ensureRawLots(code);if(layers.length){layers.slice().reverse().forEach(l=>lots.unshift({qty:Number(l.qty)||0,rate:Number(l.rate)||0,date:l.date||new Date().toISOString()}));}else lots.push({qty:Math.abs(Number(t.qty)||0),rate:Number(t.saleRate||r.rate||0),date:new Date().toISOString()});r.rate=getRawAverageRate(code);} const ix=transactions.indexOf(t);if(ix>=0)transactions.splice(ix,1);save();renderRawSaleEntries();showNextRawSaleInvoiceNo(); } function setupRawSale(){ const d=$('rawSaleDate');if(d&&!d.value)d.value=new Date().toISOString().slice(0,10);showNextRawSaleInvoiceNo();renderRawSaleCart();renderRawSaleEntries(); const m=$('rawSaleMaterial'),mb=$('rawSaleMaterialSuggest'); if(m&&mb){ const renderMaterials=()=>{ const q=m.value.trim().toLowerCase();mb.innerHTML=''; const list=(rawMaterials||[]).filter(r=>{ const name=String(r.name||'').toLowerCase(),code=String(r.code||'').toLowerCase(); return !q || name.includes(q) || code.includes(q); }).slice(0,10); list.forEach(r=>{ const x=document.createElement('div'); x.textContent=r.name+' — '+r.code+' (Stock: '+Number(r.stock||0).toFixed(3)+' '+(r.unit||'KG')+')'; x.style.cssText='padding:10px;background:#fff;border-bottom:1px solid #ddd;cursor:pointer'; x.onmousedown=e=>{e.preventDefault();m.value=r.name;m.dataset.selectedCode=r.code;mb.style.display='none';}; mb.appendChild(x); }); mb.style.display=mb.children.length?'block':'none'; }; m.addEventListener('input',()=>{m.dataset.selectedCode='';renderMaterials();}); m.addEventListener('focus',renderMaterials); m.addEventListener('click',renderMaterials); document.addEventListener('click',e=>{if(e.target!==m&&!mb.contains(e.target))mb.style.display='none';}); } const c=$('rawSaleCustomer'),cb=$('rawSaleCustomerSuggest'); if(c&&cb){ const renderCustomers=()=>{ const q=c.value.trim().toLowerCase();cb.innerHTML=''; const list=getCustomerMaster().filter(x=>String(x.name||'').toLowerCase().includes(q)).slice(0,10); list.forEach(x=>{ const d=document.createElement('div');d.textContent=x.name;d.style.cssText='padding:10px;background:#fff;border-bottom:1px solid #ddd;cursor:pointer'; d.onmousedown=e=>{e.preventDefault();c.value=x.name;cb.style.display='none';}; cb.appendChild(d); }); cb.style.display=cb.children.length?'block':'none'; }; c.addEventListener('input',renderCustomers); c.addEventListener('focus',renderCustomers); c.addEventListener('click',renderCustomers); document.addEventListener('click',e=>{if(e.target!==c&&!cb.contains(e.target))cb.style.display='none';}); } $('rawSaleAddItem')?.addEventListener('click',addRawSaleItem);$('rawSaleSave')?.addEventListener('click',saveRawSaleInvoice);$('rawSalePrint')?.addEventListener('click',()=>printRawSaleInvoice(rawSaleLastInvoiceRows,$('rawSaleInvoiceNo').value,$('rawSaleCustomer').value,'Last Invoice')); } function getSystemDateISO(){const d=new Date();return d.getFullYear()+'-'+String(d.getMonth()+1).padStart(2,'0')+'-'+String(d.getDate()).padStart(2,'0');} let dispatchCart=[]; function renderDispatchCart(){ const body=$('dispatchCartTable')?.querySelector('tbody');if(!body)return; let taxable=0,tax=0,grand=0; body.innerHTML=dispatchCart.map((x,n)=>{ const a=x.qty*x.rate,t=a*x.taxRate/100,g=a+t;taxable+=a;tax+=t;grand+=g; return `${x.name}${x.qty.toFixed(3)}${x.unit}₹${x.rate.toFixed(2)}₹${a.toFixed(2)}₹${t.toFixed(2)}₹${g.toFixed(2)}`; }).join('')||'No items added'; $('dispatchCartTotal').textContent=taxable.toFixed(2);$('dispatchCartTaxTotal').textContent=tax.toFixed(2);$('dispatchCartGrandTotal').textContent=grand.toFixed(2); document.querySelectorAll('[data-dc-del]').forEach(b=>b.onclick=()=>{dispatchCart.splice(Number(b.dataset.dcDel),1);renderDispatchCart();}); } function addDispatchItem(){ const input=$('dispatchCode'),code=input?.dataset.selectedCode||input?.value.trim(); const i=items.find(x=>String(x.code)===String(code))||items.find(x=>String(x.name||'').toLowerCase()===String(input?.value||'').trim().toLowerCase()); const q=Number($('dispatchQty').value)||0,r=Number($('dispatchRate').value)||0,taxRate=Number($('dispatchTaxRate').value)||0; if(!i||q<=0)return alert('Finished Good અને valid Quantity નાખો.'); if(q>Number(i.stock||0))return alert('Insufficient stock. Available: '+Number(i.stock||0).toFixed(3)+' '+(i.unit||'')); dispatchCart.push({code:i.code,name:i.name,unit:i.unit,qty:q,rate:r,taxRate,remark:$('dispatchRemark').value.trim()}); $('dispatchCode').value='';$('dispatchCode').dataset.selectedCode='';$('dispatchQty').value='';$('dispatchRate').value='';$('dispatchTaxRate').value='18';$('dispatchTaxAmount').value='';$('dispatchAmount').value='';$('dispatchGrandTotal').value='';$('dispatchRemark').value=''; renderDispatchCart(); } function dispatch(){ const dispatchDate=$('dispatchDate')?.value || getSystemDateISO(); const customer=$('dispatchCustomer').value.trim(); if(!customer)return alert('Customer Name નાખો.'); if(!dispatchCart.length){ // Backward-compatible: if user has filled the item fields, add it automatically. const code=$('dispatchCode')?.dataset.selectedCode||$('dispatchCode')?.value.trim(); if(code && Number($('dispatchQty')?.value)>0)addDispatchItem(); } if(!dispatchCart.length)return alert('ઓછામાં ઓછો એક Finished Good Item Add કરો.'); const stockNeed={}; for(const x of dispatchCart)stockNeed[x.code]=(stockNeed[x.code]||0)+Number(x.qty||0); for(const code in stockNeed){ const it=items.find(i=>String(i.code)===String(code)); if(!it||stockNeed[code]>Number(it.stock||0))return alert('Insufficient stock: '+(it?.name||code)+' — Required '+stockNeed[code].toFixed(3)+' '+(it?.unit||'')+', Available '+Number(it?.stock||0).toFixed(3)+' '+(it?.unit||'')); } const billNo=getNextDispatchBillNo(); dispatchCart.forEach(x=>{ const i=items.find(it=>String(it.code)===String(x.code)); const q=Number(x.qty)||0,r=Number(x.rate)||0,taxRate=Number(x.taxRate)||0,amount=q*r,tax=amount*taxRate/100; i.stock-=q; addTxn('DISPATCH','',i.code,-q,i.unit); const tr=transactions[transactions.length-1]; tr.date=dispatchDate;tr.billNo=billNo;tr.customer=customer;tr.dispatchRate=r;tr.amount=amount;tr.taxRate=taxRate;tr.tax=tax;tr.grandTotal=amount+tax;tr.remark=x.remark||'';tr.itemName=i.name; }); save();renderDispatchEntries();msg('dispatchMsg','Dispatch saved. Bill No. '+billNo+' — '+dispatchCart.length+' item(s).'); dispatchCart=[];renderDispatchCart(); $('dispatchCustomer').value=''; if($('dispatchDate') && !$('dispatchDate').value)$('dispatchDate').value=getSystemDateISO(); showNextDispatchBillNo(); } function deleteTransaction(ref){ const rows=transactions.filter(t=>t.ref===ref); if(!rows.length)return; const first=rows[0]; if(first.type==='JOB WORK ISSUE'||first.type==='JOB WORK RECEIVE'){ const msg=first.type==='JOB WORK ISSUE' ? '⚠️ Job Work Issue delete કરશો તો તેની Vendor Stock entry પણ remove થશે અને ADR stock પાછો આવશે.\\n\\nOK કરો?' : '⚠️ Job Work Receive delete કરશો તો Component Stock reverse થશે અને Vendor Stockમાં material પાછું જશે.\\n\\nOK કરો?'; if(!confirm(msg))return; }else{ if(!confirm('આ transaction delete કરીને stock reverse કરવો છે?'))return; } for(const t of rows){ const qty=Number(t.qty)||0; if(!String(t.item||'').startsWith('RM:') && t.type!=='JOB WORK RECEIVE'){ const i=items.find(x=>x.code===t.item); if(i)i.stock-=qty; } if(String(t.item||'').startsWith('RM:')){ const code=String(t.item).replace(/^RM:/,''); const r=rawMaterials.find(x=>x.code===code); if(t.type==='JOB WORK ISSUE'){ const amount=Number(t.issueQty||Math.abs(qty)); const vendor=String(t.vendor||'').trim().toLowerCase(); // Reverse ADR stock. if(r&&amount>0){ r.stock+=amount; const lots=ensureRawLots(code); const rate=Number(t.issueRate??r.rate??0); lots.push({qty:amount,rate,date:new Date().toISOString()}); r.rate=getRawAverageRate(code); } // Remove the linked Vendor Stock balance created by this issue. let remaining=amount; for(const b of jobwork.slice()){ if(remaining<=0.000001)break; if(String(b.vendor||'').trim().toLowerCase()!==vendor)continue; if(String(b.raw||'').trim().toLowerCase()!==code.toLowerCase())continue; const unit=String(b.unit||'KG').toUpperCase(); const qkg=unit==='G'?Number(b.qty||0)/1000:Number(b.qty||0); const take=Math.min(qkg,remaining); b.qty-=unit==='G'?take*1000:take; remaining-=take; if(Number(b.qty)<=0.000001)jobwork=jobwork.filter(x=>x!==b); } }else if(r){ // Normal Raw Material purchase/inward delete. r.stock-=qty; if(t.type==='RAW MATERIAL COMPANY INWARD'||t.type==='RAW MATERIAL PURCHASE'){ const lots=ensureRawLots(code); const rate=Number(t.purchaseRate??t.inwardRate??t.rate??0); let li=lots.findIndex(l=>Math.abs(Number(l.qty)-qty)<0.000001&&Math.abs(Number(l.rate)-rate)<0.000001); if(li<0)li=lots.findIndex(l=>Math.abs(Number(l.rate)-rate)<0.000001&&Number(l.qty)>=qty); if(li>=0){lots[li].qty-=qty;if(lots[li].qty<=0.000001)lots.splice(li,1);} } r.rate=getRawAverageRate(code); } } if(t.type==='JOB WORK RECEIVE'){ const comp=items.find(x=>x.code===t.item); if(comp)comp.stock-=qty; // Reverse the Vendor Stock consumption from this Receive. (t.rmConsumptionDetails||[]).forEach(d=>{ const key=String(t.vendor||'')+'|'+d.raw; const b=jobwork.find(x=>x.key===key); if(b)b.qty+=Number(d.qty)||0; else jobwork.push({key,vendor:String(t.vendor||''),raw:d.raw,qty:Number(d.qty)||0,unit:d.unit||'KG'}); }); } } transactions=transactions.filter(t=>t.ref!==ref); save();render(); } function refreshDropdowns(){} document.addEventListener('click',function(e){document.querySelectorAll('.suggestbox').forEach(b=>{if(!b.parentElement.contains(e.target))b.style.display='none';});}); function loadDispatchRateFromMaster(){ const el=$('dispatchCode'),rateEl=$('dispatchRate');if(!el||!rateEl)return; const code=String(el.dataset.selectedCode||'').trim().toLowerCase(); const name=String(el.value||'').trim().toLowerCase(); const master=getFgRateMaster(); const x=master.find(r=>String(r.itemCode||'').trim().toLowerCase()===code)|| master.find(r=>String(r.itemName||'').trim().toLowerCase()===name); rateEl.value=x?Number(x.rate||0).toFixed(2):''; dispatchUpdateAmount(); } function setupAutocomplete(input, box, filterFn){ if(!input || !box) return; if(input.dataset.autoReady==="1") return; input.dataset.autoReady="1"; function showSuggestions(){ const q=input.value.trim().toLowerCase(); box.innerHTML=""; if(!q){ box.style.display="none"; return; } const matches=items.filter(filterFn).filter(i=>{ return (String(i.name)+" "+String(i.code)).toLowerCase().includes(q); }).slice(0,10); if(!matches.length){ box.style.display="none"; return; } matches.forEach(i=>{ const row=document.createElement("div"); row.textContent=i.name+" — "+i.code; row.style.padding="10px"; row.style.cursor="pointer"; row.onclick=function(){ input.value=i.name; input.dataset.selectedCode=i.code; box.style.display="none"; if(input.id==="dispatchCode") loadDispatchRateFromMaster(); }; box.appendChild(row); }); box.style.display="block"; } input.addEventListener("input",function(){ input.dataset.selectedCode=""; showSuggestions(); }); input.addEventListener("focus",showSuggestions); } function setupRawMaterialAutocomplete(input,box){ if(!input||!box||input.dataset.autoReady==="1")return; input.dataset.autoReady="1"; function show(){ const q=input.value.trim().toLowerCase(); box.innerHTML=""; const matches=rawMaterials.filter(r=>!q || (String(r.name)+" "+String(r.code)).toLowerCase().includes(q)).slice(0,10); if(!matches.length){box.style.display="none";return;} matches.forEach(r=>{ const row=document.createElement("div"); row.textContent=r.name+" — "+r.code; row.style.padding="10px";row.style.cursor="pointer"; row.onclick=()=>{input.value=r.name;input.dataset.selectedCode=r.code;box.style.display="none"; const rateEl=document.getElementById("rmPurchaseRate"); if(rateEl)rateEl.value=Number(r.rate||0).toFixed(2);}; box.appendChild(row); }); box.style.display="block"; } input.addEventListener("input",()=>{input.dataset.selectedCode="";show();}); input.addEventListener("focus",show); } function setupAllAutocomplete(){ setupAutocomplete(document.getElementById("bomProduct"),document.getElementById("productSuggest"),i=>i.cat==="Finished Goods"); const bp=document.getElementById("bomProduct"), bs=document.getElementById("productSuggest"); if(bp && bs && !bp.dataset.fgAddReady){ bp.dataset.fgAddReady="1"; bp.addEventListener("input",()=>{ setTimeout(()=>{ const q=bp.value.trim(); if(!q)return; const exists=items.some(i=>String(i.name||"").trim().toLowerCase()===q.toLowerCase()&&i.cat==="Finished Goods"); if(exists)return; let btn=document.getElementById("addBomProductFG"); if(!btn){btn=document.createElement("div");btn.id="addBomProductFG";btn.style.cssText="padding:9px;background:#eef6ff;border:1px solid #c8dcf5;cursor:pointer;font-weight:600";bs.appendChild(btn);} btn.textContent='➕ Add "'+q+'" as Finished Goods'; btn.onclick=()=>{ const code="FG-"+Date.now().toString().slice(-6); items.push({code,name:q,cat:"Finished Goods",unit:"PCS",weight:0,stock:0,min:0}); save();refreshDropdowns();bp.value=q;bp.dataset.selectedCode=code;bs.style.display="none";render(); }; bs.style.display="block"; },80); }); } setupAutocomplete(document.getElementById("purchaseCode"),document.getElementById("itemSuggestPurchase"),i=>true); setupAutocomplete(document.getElementById("productionCode"),document.getElementById("productSuggestProduction"),i=>i.cat==="Finished Goods"); setupAutocomplete(document.getElementById("dispatchCode"),document.getElementById("productSuggestDispatch"),i=>i.cat==="Finished Goods"); const dc=document.getElementById("dispatchCode"); if(dc){dc.addEventListener("change",loadDispatchRateFromMaster);dc.addEventListener("blur",function(){setTimeout(loadDispatchRateFromMaster,100);});} setupRawMaterialAutocomplete(document.getElementById("rmPurchase"),document.getElementById("rmPurchaseSuggest")); setupAutocomplete(document.getElementById("jwComponent"),document.getElementById("componentSuggest"),i=>true); document.querySelectorAll(".bomCode").forEach(input=>{ const box=input.parentElement.querySelector(".bomSuggest"); setupAutocomplete(input,box,i=>true); }); } function setupVendorSuggest(inputId,boxId){ const input=$(inputId),box=$(boxId);if(!input||!box)return; input.addEventListener('input',function(){const q=input.value.trim().toLowerCase();box.innerHTML='';if(!q){box.style.display='none';return;} const list=vendors.filter(v=>v.name.toLowerCase().includes(q)).slice(0,10); list.forEach(v=>{const d=document.createElement('div');d.textContent=v.name;d.style.padding='10px';d.onclick=()=>{input.value=v.name;box.style.display='none';if(inputId==='jwReceiveVendor' && typeof updateAutoJobRate==='function')updateAutoJobRate();};box.appendChild(d);}); box.style.display=list.length?'block':'none'; }); } function setupItemSuggest(inputId,boxId,filter){ const input=$(inputId),box=$(boxId);if(!input||!box)return; input.addEventListener('input',function(){const q=input.value.trim().toLowerCase();box.innerHTML='';if(!q){box.style.display='none';return;} const list=items.filter(filter).filter(i=>(i.name+' '+i.code).toLowerCase().includes(q)).slice(0,10); list.forEach(i=>{const d=document.createElement('div');d.textContent=i.name+' — '+i.code;d.style.padding='10px';d.onclick=()=>{input.value=i.name;input.dataset.selectedCode=i.code;box.style.display='none';if(inputId==='jwComponent'){ $('jwComponentWeight').value=i.weight||0; updateJWConsumption(); if(typeof updateAutoJobRate==='function')updateAutoJobRate(); }};box.appendChild(d);}); box.style.display=list.length?'block':'none'; }); } function setupRawMaterialSuggest(inputId,boxId){ const input=$(inputId),box=$(boxId);if(!input||!box)return; input.addEventListener('input',function(){const q=input.value.trim().toLowerCase();box.innerHTML='';if(!q){box.style.display='none';return;} const list=rawMaterials.filter(i=>(i.name+' '+i.code).toLowerCase().includes(q)).slice(0,10); list.forEach(i=>{const d=document.createElement('div');d.textContent=i.name+' — '+i.code;d.style.padding='10px';d.onclick=()=>{input.value=i.name;input.dataset.selectedCode=i.code;box.style.display='none';};box.appendChild(d);}); box.style.display=list.length?'block':'none'; }); } function setupJobWorkSuggestions(){ setupVendorSuggest('jwVendor','vendorSuggest');setupVendorSuggest('jwIssueVendor','issueVendorSuggest');setupVendorSuggest('jwReceiveVendor','receiveVendorSuggest'); setupRawMaterialSuggest('jwRaw','rawSuggest'); setupItemSuggest('jwComponent','componentSuggest',i=>i.cat==='Component'||i.cat==='Finished Goods'); } function renderVendorMasterV223(){ const body=$('vendorTable');if(!body)return; const list=Array.isArray(vendors)?vendors:[]; body.innerHTML=list.map((v,n)=>`${String(v.name||'')}`).join('')||'No vendors added'; body.querySelectorAll('[data-vendor-del-v223]').forEach(b=>b.onclick=()=>{ const i=Number(b.dataset.vendorDelV223);if(!Number.isInteger(i)||!vendors[i])return; if(!confirm('Delete this vendor?'))return; vendors.splice(i,1);save();renderVendorMasterV223(); }); } function addVendor(){ const name=$('jwVendor').value.trim();if(!name)return alert('Vendor Name નાખો.'); if(vendors.some(v=>String(v.name||'').toLowerCase()===name.toLowerCase()))return alert('Vendor already exists.'); vendors.push({id:Date.now(),name});save();$('jwVendor').value='';renderVendorMasterV223();alert('Vendor Masterમાં add થયું.'); } function updateJWConsumption(){ const comp=items.find(i=>i.code===$('jwComponent').dataset.selectedCode)||findItemByText($('jwComponent').value); const qty=Number($('jwReceiveQty').value)||0; const grams=(Number(comp?.weight)||0)*qty; $('jwComponentWeight').value=comp?Number(comp.weight||0):''; $('jwConsumption').textContent=comp&&qty>0?'Raw Material Consumption: '+grams.toFixed(3)+' gram ('+(grams/1000).toFixed(3)+' KG)':''; } function setupRawPurchaseSuggest(){ const input=$('rmPurchase'),box=$('rmPurchaseSuggest'); if(!input||!box)return; input.addEventListener('input',function(){ input.dataset.selectedCode=''; const q=input.value.trim().toLowerCase(); box.innerHTML=''; if(!q){box.style.display='none';return;} const list=rawMaterials.filter(r=>(r.name+' '+r.code).toLowerCase().includes(q)).slice(0,10); list.forEach(r=>{ const d=document.createElement('div'); d.textContent=r.name+' — '+r.code; d.style.padding='10px'; d.onclick=()=>{input.value=r.name;input.dataset.selectedCode=r.code;$('rmPurchaseRate').value=getRawAverageRate(r.code)||r.rate||'';box.style.display='none';}; box.appendChild(d); }); box.style.display=list.length?'block':'none'; }); } function purchaseRawMaterial(){ const inwardDate=$('rmPurchaseDate').value || new Date().toISOString().slice(0,10); const supplier=$('rmPurchaseSupplier').value.trim(); const input=$('rmPurchase'); const r=rawMaterials.find(x=>x.code===(input.dataset.selectedCode||input.value.trim()))|| rawMaterials.find(x=>x.name.toLowerCase()===input.value.trim().toLowerCase()); const qty=Number($('rmPurchaseQty').value)||0; const rate=Number($('rmPurchaseRate').value)||0; if(!supplier)return alert('Supplier select કરો.'); if(!r)return alert('Raw Material select કરો.'); if(qty<=0)return alert('Quantity નાખો.'); if(rate<0)return alert('Rate ખોટો છે.'); r.stock=Number(r.stock||0)+qty; addRawMaterialLot(r.code,qty,rate); r.rate=getRawAverageRate(r.code); const ref='RMI-'+String(++rmPurchaseNo).padStart(5,'0'); addTxn('RAW MATERIAL COMPANY INWARD',ref,'RM:'+r.code,qty,r.unit); const tr=transactions[transactions.length-1]; tr.date=inwardDate; tr.supplier=supplier; tr.inwardRate=rate; tr.inwardRef=$('rmPurchaseRef').value.trim(); tr.amount=qty*rate; tr.taxRate=Math.max(0,Number($('rmPurchaseTaxRate').value||18)); tr.tax=tr.amount*tr.taxRate/100; tr.grandTotal=tr.amount+tr.tax; save(); msg('rmPurchaseMsg','Raw Material Stock add થયું. No: '+ref+' | '+r.name+' | '+qty.toFixed(3)+' '+r.unit+' | Rate ₹'+rate.toFixed(3)+' | Total Stock '+Number(r.stock).toFixed(3)); $('rmPurchaseDate').value=new Date().toISOString().slice(0,10);$('rmPurchaseTaxRate').value='18';$('rmPurchaseSupplier').value='';$('rmPurchaseSupplier').dataset.selectedSupplier='';$('rmPurchase').value='';$('rmPurchase').dataset.selectedCode='';$('rmPurchaseQty').value='';$('rmPurchaseRate').value='';$('rmPurchaseRef').value=''; } function addRawMaterial(){ const code=$('rmCode').value.trim(),name=$('rmName').value.trim(); const rate=Number($('rmRate').value)||0,opening=Number($('rmOpening').value)||0; if(!code||!name)return alert('Material Code અને Material Name નાખો.'); if(rawMaterials.some(x=>x.code===code))return alert('Material Code already exists.'); rawMaterials.push({code,name,unit:$('rmUnit').value,rate,stock:opening,min:Number($('rmMin').value)||0}); if(opening>0)addRawMaterialLot(code,opening,rate); save();['rmCode','rmName','rmRate','rmOpening','rmMin'].forEach(id=>$(id).value=''); render();refreshDropdowns(); if($('rawMaterialMasterAddBox'))$('rawMaterialMasterAddBox').style.display='none'; if($('showRawMaterialMasterBtn'))$('showRawMaterialMasterBtn').style.display='inline-block'; } function editRawMaterial(code){ const r=rawMaterials.find(x=>x.code===code);if(!r)return; const n=prompt('Material Name',r.name);if(n===null)return; const rate=prompt('Rate / KG',r.rate);if(rate===null)return; const min=prompt('Minimum Stock',r.min);if(min===null)return; r.name=n;r.rate=Number(rate)||0;r.min=Number(min)||0;save(); } function deleteRawMaterial(code){ if(jobwork.some(x=>x.raw===code)||transactions.some(t=>t.item===code))return alert('આ Raw Material transaction/job workમાં વપરાયેલ છે.'); if(confirm('Delete '+code+'?')){rawMaterials=rawMaterials.filter(x=>x.code!==code);save();} } function findItemByText(v){v=v.trim().toLowerCase();return items.find(i=>i.code.toLowerCase()===v)||items.find(i=>i.name.toLowerCase()===v);} function issueToVendor(){ const vendor=$('jwIssueVendor').value.trim(); const raw=rawMaterials.find(x=>x.code===$('jwRaw').dataset.selectedCode)||rawMaterials.find(x=>x.code===$('jwRaw').value.trim())||rawMaterials.find(x=>x.name.toLowerCase()===$('jwRaw').value.trim().toLowerCase()); const qty=Number($('jwIssueQty').value)||0;const ref='JW-'+String(++jwIssueNo).padStart(5,'0'); if(!vendor||!raw||qty<=0)return alert('Vendor, Raw Material અને Qty નાખો.'); if(raw.stockx.key===key); if(old)old.qty+=qty;else jobwork.push({key,vendor,raw:raw.code,qty,unit:raw.unit}); addTxn('JOB WORK ISSUE',ref,'RM:'+raw.code,-qty,raw.unit); const _issueTxn=transactions[transactions.length-1]; _issueTxn.vendor=vendor; _issueTxn.issueRate=Number(raw.rate||0); _issueTxn.issueQty=qty; save();msg('jwIssueMsg','Raw Material vendorને issue થયું. Challan No: '+ref); $('jwIssueVendor').value='';$('jwRaw').value='';$('jwIssueQty').value=''; } function setupRateSuggestions(){ setupVendorSuggest('rateVendor','rateVendorSuggest'); setupItemSuggest('rateComponent','rateComponentSuggest',i=>i.cat==='Component'||i.cat==='Finished Goods'); } function getJobWorkRate(vendor,code){ const norm=v=>String(v??'').trim().toLowerCase().replace(/\s+/g,' '); const compact=v=>norm(v).replace(/[^a-z0-9]/g,''); const v=norm(vendor), vc=compact(vendor), c=norm(code); const item=items.find(i=>norm(i.code)===c)||items.find(i=>norm(i.name)===c)||items.find(i=>compact(i.code)===compact(code))||items.find(i=>compact(i.name)===compact(code)); const itemCode=norm(item?item.code:c), itemName=norm(item?item.name:c); const itemCodeC=compact(itemCode), itemNameC=compact(itemName), cC=compact(c); const isSameComponent=x=>{ const xc=norm(x.component), xcc=compact(x.component); return xc===itemCode || xc===itemName || xc===c || xcc===itemCodeC || xcc===itemNameC || xcc===cC; }; // 1) Always prefer the exact Vendor + Component rate. let r=jobworkRates.find(x=>{ const xv=norm(x.vendor), xvc=compact(x.vendor); return (xv===v || xvc===vc) && isSameComponent(x); }); // 2) If the vendor/component text differs slightly, allow a unique vendor match. if(!r && v){ const vendorMatches=jobworkRates.filter(x=>{ const xv=norm(x.vendor), xvc=compact(x.vendor); return (xv===v || xvc===vc) && isSameComponent(x); }); if(vendorMatches.length) r=vendorMatches[vendorMatches.length-1]; } // 3) Component-only fallback. If several rates exist, use the most recently // saved matching rate instead of returning 'Rate not set'. This also supports // older records where the vendor was not stored consistently. if(!r){ const matches=jobworkRates.filter(isSameComponent); if(matches.length) r=matches[matches.length-1]; } return r?Number(r.rate)||0:0; } function saveJobWorkRate(){ const vendorInput=$('rateVendor').value.trim(); const comp=findItemByText($('rateComponent').value); const rate=Number($('rateValue').value)||0; const vObj=vendors.find(v=>v.name.toLowerCase()===vendorInput.toLowerCase()); const vendor=vObj?vObj.name:vendorInput; if(!vendor||!comp||rate<=0)return alert('Vendor, Component અને Rate નાખો.'); const old=jobworkRates.find(x=>x.vendor.toLowerCase()===vendor.toLowerCase()&&x.component===comp.code); if(old)old.rate=rate;else jobworkRates.push({vendor,component:comp.code,rate}); save();renderJobWorkRates(); renderPurchaseEntries();msg('rateMsg','Job Work Rate Masterમાં save થયું: '+vendor+' → '+comp.name+' = ₹'+rate.toFixed(3)); $('rateVendor').value='';$('rateComponent').value='';$('rateValue').value=''; } function renderJobWorkRates(){ if(!$('rateTable'))return; $('rateTable').innerHTML=jobworkRates.map((r,idx)=>{ const c=items.find(i=>i.code===r.component); return `${r.vendor}${c?c.name:r.component}₹${fmtRate2(r.rate)}`; }).join(''); document.querySelectorAll('[data-rate-del]').forEach(b=>b.onclick=()=>{if(confirm('Delete this rate?')){jobworkRates.splice(Number(b.dataset.rateDel),1);save();}}); } function receiveFromVendor(){ const receiveDate=$('jwReceiveDate').value || new Date().toISOString().slice(0,10); const vendor=$('jwReceiveVendor').value.trim(); const comp=items.find(i=>i.code===$('jwComponent').dataset.selectedCode)||findItemByText($('jwComponent').value); const qty=Number($('jwReceiveQty').value)||0; const rate=getJobWorkRate(vendor,comp?comp.code:$('jwComponent').value); $('jwJobRate').value=rate>0?rate.toFixed(2):'Rate not set'; if(!vendor||!comp||qty<=0)return alert('Vendor, Component અને Qty નાખો.'); if(rate<=0)return alert('આ Vendor + Component માટે Rate set નથી.'); if(!comp.weight)return alert('Componentનું Weight Item Masterમાં add કરો.'); const consumptionKG=(Number(comp.weight)*qty)/1000; const balances=jobwork.filter(x=>x.vendor.toLowerCase()===vendor.toLowerCase()&&Number(x.qty)>0.000001); let remaining=consumptionKG,rawCost=0,details=[]; // IMPORTANT: // Raw material is deducted from ADR stock ONLY at Job Work Issue. // At Component Receive, deduct ONLY Vendor Stock. for(const b of balances){ if(remaining<=0)break; const raw=rawMaterials.find(i=>i.code===b.raw);if(!raw)continue; const unit=b.unit||raw.unit||'KG'; const availableKG=String(unit).toUpperCase()==='G'?Number(b.qty)/1000:Number(b.qty); const takeKG=Math.min(availableKG,remaining); if(takeKG<=0)continue; // Calculate FIFO costing without changing ADR stock/lots. let left=takeKG,cost=0; for(const lot of ensureRawLots(raw.code)){ if(left<=0)break; const take=Math.min(left,Number(lot.qty)||0); cost+=take*(Number(lot.rate)||0); left-=take; } rawCost+=cost; if(String(unit).toUpperCase()==='G')b.qty-=takeKG*1000;else b.qty-=takeKG; remaining-=takeKG; details.push({raw:raw.code,qty:takeKG,unit:'KG',rate:takeKG?cost/takeKG:0}); } if(remaining>0.000001)return alert('Vendor પાસે Raw Material ઓછું છે. Required '+consumptionKG.toFixed(3)+' KG.'); const ref='JWR-'+String(++jwReceiveNo).padStart(5,'0'); comp.stock+=qty; const amount=qty*rate; addTxn('JOB WORK RECEIVE',ref,comp.code,qty,comp.unit); const tr=transactions[transactions.length-1]; tr.date=receiveDate; tr.jobRate=rate;tr.jobAmount=amount;tr.vendor=vendor;tr.rmConsumed=consumptionKG; tr.rawMaterialCost=rawCost;tr.componentCost=(rawCost/qty)||0;tr.rmConsumptionDetails=details; tr.taxRate=Math.max(0,Number($('jwTaxRate').value||18)); tr.tax=amount*tr.taxRate/100; tr.grandTotal=amount+tr.tax; save(); msg('jwReceiveMsg','Component received. Challan No: '+ref+' | Rate ₹'+rate.toFixed(2)+' | Job Work ₹'+amount.toFixed(2)+' | Material Cost ₹'+rawCost.toFixed(2)+' | ADR stock unchanged.'); $('jwReceiveDate').value=new Date().toISOString().slice(0,10);$('jwTaxRate').value='18';$('jwReceiveVendor').value='';$('jwComponent').value='';$('jwComponentWeight').value='';$('jwReceiveQty').value='';$('jwJobRate').value='';$('jwConsumption').textContent='';$('jwJobAmount').textContent=''; } function showDashboardFilter(type){ const box=$('dashboardDetails'),title=$('dashboardDetailsTitle'),table=$('dashboardDetailsTable'); let list=[],label=''; if(type==='raw'){list=rawMaterials.map(r=>({code:r.code,name:r.name,cat:'Raw Material',unit:r.unit,weight:'-',stock:r.stock,min:r.min}));label='Raw Material Stock';} else if(type==='vendor'){ const by={}; jobwork.filter(x=>Number(x.qty)>0.000001).forEach(x=>{ const kg=String(x.unit).toUpperCase()==='G'?Number(x.qty)/1000:Number(x.qty); const key=x.vendor+'|'+x.raw; by[key]=(by[key]||0)+kg; }); list=Object.entries(by).map(([key,stock])=>{ const [vendor,raw]=key.split('|'); const r=rawMaterials.find(i=>i.code===raw); return {code:vendor,name:r?r.name:raw,cat:'Vendor Raw Material',unit:'KG',weight:'-',stock:stock,min:'-'}; }); label='Vendor Raw Material Stock'; } else if(type==='fg'){list=items.filter(i=>i.cat==='Finished Goods').map(i=>({code:i.code,name:i.name,cat:i.cat,unit:i.unit,weight:i.weight,stock:i.stock,min:i.min}));label='Finished Goods Stock';} else if(type==='low'){ const rm=rawMaterials.filter(r=>Number(r.stock)<=Number(r.min)).map(r=>({code:r.code,name:r.name,cat:'Raw Material',unit:r.unit,weight:'-',stock:r.stock,min:r.min})); const it=items.filter(i=>Number(i.stock)<=Number(i.min)).map(i=>({code:i.code,name:i.name,cat:i.cat,unit:i.unit,weight:i.weight,stock:i.stock,min:i.min})); list=rm.concat(it);label='Low Stock Items'; } else { list=items.map(i=>({code:i.code,name:i.name,cat:i.cat,unit:i.unit,weight:i.weight,stock:i.stock,min:i.min}));label='All Items'; } title.textContent=label;table.innerHTML=list.length?list.map(i=>`${i.code}${i.name}${i.cat}${i.unit}${i.weight}${i.stock}${i.min}`).join(''):'No data'; box.style.display='block'; } function setupDashboardCards(){ document.querySelectorAll('.dashCard').forEach(c=>c.onclick=()=>showDashboardFilter(c.dataset.filter)); } function editPurchase(id){ const t=transactions.find(x=>String(x.id)===String(id)); if(!t)return; const oldCode=String(t.item||'').replace(/^RM:/,''); const oldR=rawMaterials.find(x=>x.code===oldCode); if(!oldR)return; const oldQty=Number(t.qty)||0; const oldRate=Number(t.purchaseRate??t.inwardRate??t.rate??0); const date=prompt('Inward Date (YYYY-MM-DD)',t.date||''); if(date===null)return; const supplier=prompt('Supplier',t.supplier||''); if(supplier===null)return; const material=prompt('Raw Material Name / Code',oldR.name+' — '+oldR.code); if(material===null)return; const q=prompt('Quantity',oldQty); if(q===null)return; const rate=prompt('Rate',oldRate); if(rate===null)return; const ref=prompt('Invoice / Ref',t.inwardRef||''); if(ref===null)return; const gst=prompt('GST %',Number(t.taxRate??18)); if(gst===null)return; const qty=Number(q),newRate=Number(rate),newGst=Number(gst); const newR=rawMaterials.find(x=>x.code===material.trim())||rawMaterials.find(x=>x.name.toLowerCase()===material.trim().toLowerCase())||rawMaterials.find(x=>(x.name+' — '+x.code).toLowerCase()===material.trim().toLowerCase()); if(!supplier.trim())return alert('Supplier જરૂરી છે.'); if(!newR)return alert('Raw Material મળ્યું નથી.'); if(!Number.isFinite(qty)||qty<=0)return alert('Quantity ખોટી છે.'); if(!Number.isFinite(newRate)||newRate<0)return alert('Rate ખોટો છે.'); if(oldR.stockMath.abs(Number(l.qty)-oldQty)<0.000001&&Math.abs(Number(l.rate)-oldRate)<0.000001); if(idx<0)idx=lots.findIndex(l=>Math.abs(Number(l.rate)-oldRate)<0.000001&&Number(l.qty)>=oldQty); if(idx>=0){lots[idx].qty-=oldQty;if(lots[idx].qty<=0.000001)lots.splice(idx,1);} oldR.rate=getRawAverageRate(oldCode); newR.stock=Number(newR.stock||0)+qty; addRawMaterialLot(newR.code,qty,newRate); newR.rate=getRawAverageRate(newR.code); t.date=date.trim()||t.date; t.supplier=supplier.trim(); t.item='RM:'+newR.code; t.qty=qty; t.unit=newR.unit; t.inwardRate=newRate; t.inwardRef=ref.trim(); t.amount=qty*newRate; if(!Number.isFinite(newGst)||newGst<0)return alert('GST % ખોટો છે.'); t.taxRate=newGst;t.tax=t.amount*newGst/100;t.grandTotal=t.amount+t.tax; save();render(); } function deletePurchase(id){ const t=transactions.find(x=>String(x.id)===String(id)); if(!t)return; const code=String(t.item||'').replace(/^RM:/,''); const r=rawMaterials.find(x=>x.code===code); if(!r)return; if(Number(r.stock)Math.abs(Number(l.qty)-Number(t.qty))<0.000001&&Math.abs(Number(l.rate)-rate)<0.000001); if(idx<0)idx=lots.findIndex(l=>Math.abs(Number(l.rate)-rate)<0.000001&&Number(l.qty)>=Number(t.qty)); if(idx>=0){ lots[idx].qty-=Number(t.qty); if(lots[idx].qty<=0.000001)lots.splice(idx,1); } r.rate=getRawAverageRate(code); transactions=transactions.filter(x=>String(x.id)!==String(id)); save();render(); } function updateAutoJobRate(){ const v=($('jwReceiveVendor')?.value||'').trim(); const c=items.find(i=>i.code===($('jwComponent')?.dataset.selectedCode||''))||findItemByText($('jwComponent')?.value||''); const rate=c?getJobWorkRate(v,c.code):0; $('jwJobRate').value=rate>0?Number(rate).toFixed(3):'Rate not set'; } function setupReportSelectors(){ const now=new Date(), y=now.getFullYear(), m=now.getMonth(); const sel=$('reportMonth'); if(!sel)return; sel.innerHTML=''; for(let k=0;k<24;k++){ const d=new Date(y,m-k,1), val=d.getFullYear()+'-'+String(d.getMonth()+1).padStart(2,'0'); const opt=document.createElement('option');opt.value=val;opt.textContent=d.toLocaleString('en-IN',{month:'long',year:'numeric'});sel.appendChild(opt); } $('reportVendor').innerHTML=''+vendors.map(v=>``).join(''); } function setupReportSelectors(){ const now=new Date(), y=now.getFullYear(), m=now.getMonth(); const sel=$('reportMonth'); if(!sel)return; sel.innerHTML=''; for(let k=0;k<24;k++){ const d=new Date(y,m-k,1); const val=d.getFullYear()+'-'+String(d.getMonth()+1).padStart(2,'0'); const opt=document.createElement('option'); opt.value=val; opt.textContent=d.toLocaleString('en-IN',{month:'long',year:'numeric'}); sel.appendChild(opt); } $('reportVendor').innerHTML=''+vendors.map(v=>``).join(''); } function generateJWReport(){ // Report Rate = actual Job Work Receive rate saved on each Component Receive transaction (weighted average when multiple receives exist). const month=$('reportMonth').value; const vendor=$('reportVendor').value; if(!month){alert('Month select કરો.');return;} const rows=transactions.filter(t=>{ if(t.type!=='JOB WORK RECEIVE')return false; const d=new Date(t.date); if(isNaN(d.getTime()))return false; const ym=d.getFullYear()+'-'+String(d.getMonth()+1).padStart(2,'0'); return (month==='ALL' || ym===month) && (!vendor||t.vendor===vendor); }); const grouped={}; rows.forEach(t=>{ const key=(t.vendor||'Unknown')+'|'+t.item; if(!grouped[key])grouped[key]={vendor:t.vendor||'Unknown',item:t.item,qty:0,amount:0,rm:0,rateAmount:0}; const tq=Number(t.qty)||0, tr=Number(t.jobRate??t.rate??0)||0, ta=Number(t.jobAmount??(tq*tr))||0; grouped[key].qty+=tq; grouped[key].amount+=ta; grouped[key].rateAmount+=tq*tr; grouped[key].rm+=Number(t.rmConsumed)||0; }); const data=Object.values(grouped); $('jwReportTable').innerHTML=data.length?data.map(x=>{ const it=items.find(i=>i.code===x.item); const rate=x.qty?x.rateAmount/x.qty:(x.amount/x.qty||0); return `${x.vendor}${it?it.name:x.item}${x.qty.toFixed(3)}₹${rate.toFixed(3)}₹${x.amount.toFixed(2)}${x.rm.toFixed(3)}`; }).join(''):'No Job Work Receive entries for selected month.'; const tq=data.reduce((a,x)=>a+x.qty,0); const ta=data.reduce((a,x)=>a+x.amount,0); const trm=data.reduce((a,x)=>a+x.rm,0); $('jwReportQty').textContent=tq.toFixed(3); $('jwReportAmount').textContent='₹'+ta.toFixed(2); $('jwReportRM').textContent=trm.toFixed(3)+' KG'; const monthLabel=month==='ALL'?'All Months':(()=>{const d=new Date(month+'-01T00:00:00'); return d.toLocaleString('en-IN',{month:'long',year:'numeric'});})(); $('jwReportHeader').innerHTML='

Month: '+monthLabel+'   Vendor: '+(vendor||'All Vendors')+'   Entries: '+rows.length+'

'; $('reports').style.display='block'; } function productionReportItemAutocomplete(){ const input=$('prodReportProduct'),box=$('prodReportProductSuggest'); if(!input||!box)return; function show(){ const q=input.value.trim().toLowerCase(); box.innerHTML=''; if(!q){box.style.display='none';return;} const list=(items||[]).filter(i=>{ if(String(i.cat||'')!=='Finished Goods')return false; return String(i.name||'').toLowerCase().includes(q)||String(i.code||'').toLowerCase().includes(q); }).slice(0,12); list.forEach(i=>{ const d=document.createElement('div'); d.textContent=String(i.name||'')+' — '+String(i.code||''); d.style.cssText='padding:10px 12px;background:#fff;color:#111;border-bottom:1px solid #ddd;cursor:pointer;'; d.onmousedown=e=>{e.preventDefault();input.value=String(i.name||'');input.dataset.selectedCode=String(i.code||'');box.style.display='none';}; box.appendChild(d); }); box.style.display=list.length?'block':'none'; } input.addEventListener('input',show); input.addEventListener('focus',show); input.addEventListener('keyup',show); document.addEventListener('click',e=>{if(e.target!==input&&!box.contains(e.target))box.style.display='none';}); } function generateProductionReport(){ const from=$('prodReportFrom').value; const to=$('prodReportTo').value; const productQ=$('prodReportProduct').value.trim().toLowerCase(); const rows=transactions.filter(t=>{ if(t.type!=='PRODUCTION')return false; const prodItem=items.find(i=>i.code===t.item); if(!prodItem || prodItem.cat!=='Finished Goods')return false; const d=new Date(t.date); if(isNaN(d.getTime()))return false; const ds=d.toISOString().slice(0,10); if(from&&dsto)return false; if(productQ){ const it=items.find(i=>i.code===t.item); const name=(it?it.name:t.item).toLowerCase(); if(!name.includes(productQ))return false; } return true; }); let total=0; const body=rows.slice().reverse().map(t=>{ const it=items.find(i=>i.code===t.item); const qty=Math.abs(Number(t.qty)||0); total+=qty; let cons=''; if(Array.isArray(t.materialConsumption)){ cons=t.materialConsumption.map(x=>{ const mi=items.find(i=>i.code===x.code)||rawMaterials.find(i=>i.code===x.code); return (mi?mi.name:x.code)+' × '+Number(x.qty||0).toFixed(3); }).join('
'); }else if(Array.isArray(t.bomConsumption)){ cons=t.bomConsumption.map(x=>{ const mi=items.find(i=>i.code===x.code)||rawMaterials.find(i=>i.code===x.code); return (mi?mi.name:x.code)+' × '+Number(x.qty||0).toFixed(3); }).join('
'); }else cons='-'; return `${t.date||''}${t.ref||''}${it?it.name:t.item}${qty.toFixed(3)}${t.unit||'PCS'}`; }).join(''); $('productionReportTable').querySelector('tbody').innerHTML=body||'No Finished Goods production entries found.'; $('productionReportTotal').textContent=total.toFixed(3); $('productionReportMsg').textContent=rows.length+' production entries found.'; } function getPurchaseEntries(){ return (transactions||[]).filter(t=>{ const type=String(t.type||t.transactionType||'').toUpperCase(); return type==='PURCHASE' || type==='PURCHASE ENTRY' || type==='PURCHASE_ENTRY'; }); } function renderPurchaseEntries(){ const body=$('purchaseEntryTable')?.querySelector('tbody');if(!body)return; const rows=transactions.filter(t=>t.type==='PURCHASE').slice().reverse(); body.innerHTML=rows.map((t,idx)=>{ const it=items.find(i=>i.code===t.item); const qty=Math.abs(Number(t.qty)||0),rate=Number(t.purchaseRate||0),amount=Number(t.amount??qty*rate),gstRate=Number(t.taxRate??18),gst=Number(t.tax??amount*gstRate/100),total=Number(t.grandTotal??amount+gst); const id=String(t.id||t.ref||('PURCHASE-'+idx)); return ` ${t.date||''}${t.supplier||''}${it?it.name:(t.item||'')} ${qty.toFixed(3)}${t.purchaseUnit||t.unit||''} ₹${fmtRate2(rate)}₹${amount.toFixed(2)}${t.ref||''} `; }).join('')||'No purchase entries'; document.querySelectorAll('[data-purchase-edit]').forEach(btn=>btn.onclick=()=>{ const id=btn.dataset.purchaseEdit; const t=transactions.find(x=>String(x.id||x.ref)===id); if(!t)return; const purchaseDate=prompt('Purchase Date (YYYY-MM-DD):',t.date||new Date().toISOString().slice(0,10));if(purchaseDate===null)return; const supplier=prompt('Supplier Name:',t.supplier||'');if(supplier===null)return; const qty=prompt('Quantity:',Math.abs(Number(t.qty)||0));if(qty===null)return; const unit=prompt('Unit (KG / PCS):',t.purchaseUnit||t.unit||'KG');if(unit===null)return; const rate=prompt('Rate:',Number(t.purchaseRate||0).toFixed(2));if(rate===null)return; const ref=prompt('Invoice / Ref:',t.ref||'');if(ref===null)return; const oldQty=Math.abs(Number(t.qty)||0); const it=items.find(i=>i.code===t.item); if(it)it.stock-=oldQty; t.date=String(purchaseDate).trim() || t.date || new Date().toISOString().slice(0,10); t.supplier=supplier.trim(); t.qty=Number(qty)||0; t.purchaseUnit=String(unit).toUpperCase()==='PCS'?'PCS':'KG'; t.unit=t.purchaseUnit; t.purchaseRate=Number(rate)||0; t.ref=ref.trim(); if(it)it.stock+=t.qty; save(); renderPurchaseEntries(); }); document.querySelectorAll('[data-purchase-delete]').forEach(btn=>btn.onclick=()=>{ const id=btn.dataset.purchaseDelete; const t=transactions.find(x=>String(x.id||x.ref)===id); if(!t)return; if(!confirm('આ Purchase entry delete કરીને stock reverse કરવો છે?'))return; const it=items.find(i=>i.code===t.item); if(it)it.stock-=Math.abs(Number(t.qty)||0); const ix=transactions.indexOf(t); if(ix>=0)transactions.splice(ix,1); save(); renderPurchaseEntries(); }); } function purchaseReportSupplierAutocomplete(){ const input=$('purchaseReportSupplier'),box=$('purchaseReportSupplierSuggest'); if(!input||!box)return; function suppliers(){ let a=[]; ['adr_supplier_master_v1','adr_purchase_master_v4','adr_purchase_master_v3','adr_purchase_master_v2','adr_suppliers_v1'].forEach(k=>{ try{const x=JSON.parse(localStorage.getItem(k)||'[]');if(Array.isArray(x))a=a.concat(x);}catch(e){} }); const seen=new Set(); return a.map(x=>String(x.name||x.supplier||'').trim()).filter(n=>n&&!seen.has(n.toLowerCase())&&seen.add(n.toLowerCase())); } function show(){ const q=input.value.trim().toLowerCase();box.innerHTML=''; if(!q){box.style.display='none';return;} const list=suppliers().filter(n=>n.toLowerCase().includes(q)).slice(0,12); list.forEach(n=>{ const d=document.createElement('div'); d.textContent=n; d.style.cssText='padding:10px 12px;background:#fff;color:#111;border-bottom:1px solid #ddd;cursor:pointer;'; d.onmousedown=e=>{e.preventDefault();input.value=n;box.style.display='none';}; box.appendChild(d); }); box.style.display=list.length?'block':'none'; } input.addEventListener('input',show); input.addEventListener('focus',show); input.addEventListener('keyup',show); document.addEventListener('click',e=>{if(e.target!==input&&!box.contains(e.target))box.style.display='none';}); } function generatePurchaseReport(){ try{ const from=$('purchaseReportFrom')?.value||'',to=$('purchaseReportTo')?.value||''; const sq=String($('purchaseReportSupplier')?.value||'').trim().toLowerCase(); const toISO=v=>{ const s=String(v||'').trim(); let m=s.match(/^(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/); if(m){ const a=Number(m[1]),b=Number(m[2]),y=m[3]; const mm=a>12?b:a,dd=a>12?a:b; return y+'-'+String(mm).padStart(2,'0')+'-'+String(dd).padStart(2,'0'); } m=s.match(/^(\d{4})[\/\-](\d{1,2})[\/\-](\d{1,2})/); return m?m[1]+'-'+String(m[2]).padStart(2,'0')+'-'+String(m[3]).padStart(2,'0'):''; }; const rows=(transactions||[]).filter(t=>{ const typ=String(t.type||t.transactionType||'').toUpperCase(); const ok=typ==='PURCHASE'||typ==='PURCHASE ENTRY'||typ==='PURCHASE_ENTRY'||t.supplier!=null; if(!ok)return false; const d=toISO(t.date||t.createdAt||t.timestamp),s=String(t.supplier||t.supplierName||'').toLowerCase(); return (!from||!d||d>=from)&&(!to||!d||d<=to)&&(!sq||s.includes(sq)); }); let q=0,a=0,s=''; rows.slice().reverse().forEach(t=>{ const it=(items||[]).find(x=>String(x.code||'')===String(t.item||t.itemCode||'')); const n=Math.abs(Number(t.qty??t.quantity)||0),r=Number(t.purchaseRate??t.rate??0),amt=n*r;q+=n;a+=amt; s+=`${t.date||''}${t.supplier||t.supplierName||''}${it?.name||t.itemName||t.item||''}${n.toFixed(3)}${t.purchaseUnit||t.unit||''}₹${r.toFixed(2)}₹${amt.toFixed(2)}${t.ref||t.invoice||''}`; }); $('purchaseReportTable').querySelector('tbody').innerHTML=s||'No purchase entries found'; $('purchaseReportQty').textContent=q.toFixed(3);$('purchaseReportAmount').textContent='₹'+a.toFixed(2); $('purchaseReportMsg').textContent=rows.length+' purchase entries found.'; }catch(e){if($('purchaseReportMsg'))$('purchaseReportMsg').textContent='Report error: '+e.message;} } function generatePurchaseInlineReport(){ const from=$('purchaseInlineFrom')?.value||'',to=$('purchaseInlineTo')?.value||''; const supplier=($('purchaseInlineSupplier')?.value||'').trim().toLowerCase(); const list=(transactions||[]).filter(t=>{ if(String(t.type||'').toUpperCase()!=='PURCHASE')return false; const raw=String(t.date||'');let ds='';let x=raw.match(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/); if(x)ds=x[3]+'-'+String(x[2]).padStart(2,'0')+'-'+String(x[1]).padStart(2,'0'); else{const d=new Date(raw);if(!isNaN(d))ds=d.toISOString().slice(0,10)} const s=String(t.supplier||'').toLowerCase(); return (!from||ds>=from)&&(!to||ds<=to)&&(!supplier||s.includes(supplier)); }); let q=0,a=0,rows=''; list.slice().reverse().forEach(t=>{ const it=(items||[]).find(i=>String(i.code||'')===String(t.item||''));const n=Math.abs(Number(t.qty)||0),r=Number(t.purchaseRate||0),amt=n*r;q+=n;a+=amt; rows+=`${t.date||''}${t.supplier||''}${it?it.name:(t.itemName||t.item||'')}${n.toFixed(3)}${t.purchaseUnit||t.unit||''}₹${r.toFixed(2)}₹${amt.toFixed(2)}${t.ref||''}`; }); $('purchaseInlineReportTable').querySelector('tbody').innerHTML=rows||'No purchase entries found'; $('purchaseInlineQty').textContent=q.toFixed(3);$('purchaseInlineAmount').textContent='₹'+a.toFixed(2);$('purchaseInlineReportMsg').textContent=list.length+' purchase entries found.'; } function setupPurchaseInlineSupplierSuggest(){ const i=$('purchaseInlineSupplier'),b=$('purchaseInlineSupplierSuggest');if(!i||!b)return; const names=()=>{let a=[];['adr_supplier_master_v1','adr_purchase_master_v4','adr_suppliers_v1'].forEach(k=>{try{let x=JSON.parse(localStorage.getItem(k)||'[]');if(Array.isArray(x))a=a.concat(x)}catch(e){}});return [...new Set(a.map(x=>String(x.name||x.supplier||'').trim()).filter(Boolean))]}; i.addEventListener('input',()=>{const q=i.value.toLowerCase().trim();b.innerHTML='';if(!q){b.style.display='none';return}names().filter(n=>n.toLowerCase().includes(q)).slice(0,10).forEach(n=>{let d=document.createElement('div');d.textContent=n;d.style.cssText='padding:10px;background:#fff;border-bottom:1px solid #ddd;cursor:pointer';d.onclick=()=>{i.value=n;b.style.display='none'};b.appendChild(d)});b.style.display=b.children.length?'block':'none'}); } function getCustomerMaster(){ try{ const a=JSON.parse(localStorage.getItem('adr_customer_master_v1')||'[]'); return Array.isArray(a)?a:[]; }catch(e){return []} } function saveCustomerMaster(a){localStorage.setItem('adr_customer_master_v1',JSON.stringify(a));} function renderCustomerMaster(){ const body=$('customerTable')?.querySelector('tbody');if(!body)return; const a=getCustomerMaster(); body.innerHTML=a.map((x,n)=>`${x.code||''}${x.name||''} `).join('')||'No customers added'; document.querySelectorAll('[data-customer-edit]').forEach(b=>b.onclick=()=>{ const a=getCustomerMaster(),x=a[Number(b.dataset.customerEdit)];if(!x)return; const name=prompt('Customer Name:',x.name||'');if(name===null)return; const code=prompt('Customer Code:',x.code||'');if(code===null)return; if(!name.trim())return; x.name=name.trim();x.code=code.trim();saveCustomerMaster(a);renderCustomerMaster(); }); document.querySelectorAll('[data-customer-del]').forEach(b=>b.onclick=()=>{ const a=getCustomerMaster();a.splice(Number(b.dataset.customerDel),1);saveCustomerMaster(a);renderCustomerMaster(); }); } function addCustomerMaster(){ const name=String($('customerName')?.value||'').trim(),code=String($('customerCode')?.value||'').trim(); if(!name){alert('Customer Name નાખો.');return} const a=getCustomerMaster(); if(a.some(x=>String(x.name||'').toLowerCase()===name.toLowerCase())){alert('Customer already exists.');return} a.push({name,code});saveCustomerMaster(a);renderCustomerMaster(); $('customerName').value='';$('customerCode').value=''; if($('customerMsg'))$('customerMsg').textContent='Customer saved.'; } function getFgRateMaster(){ try{ const a=JSON.parse(localStorage.getItem('adr_finished_goods_rates_v1')||'[]'); return Array.isArray(a)?a:[]; }catch(e){return []} } function saveFgRateMaster(a){localStorage.setItem('adr_finished_goods_rates_v1',JSON.stringify(a));} function getFinishedGoodsForRate(){ return (Array.isArray(items)?items:[]).filter(i=>String(i.cat||'').toLowerCase()==='finished goods'); } function renderFgRateMaster(){ const body=$('fgRateTable')?.querySelector('tbody');if(!body)return; const a=getFgRateMaster(); body.innerHTML=a.map((x,n)=>`${x.itemName||''}${x.itemCode||''}₹${Number(x.rate||0).toFixed(2)} `).join('')||'No Finished Goods rates added'; document.querySelectorAll('[data-fgr-edit]').forEach(b=>b.onclick=()=>{ const a=getFgRateMaster(),x=a[Number(b.dataset.fgrEdit)];if(!x)return; const r=prompt('Sale Rate:',Number(x.rate||0).toFixed(2));if(r===null)return; if(Number(r)<0)return; x.rate=Number(r);saveFgRateMaster(a);renderFgRateMaster(); }); document.querySelectorAll('[data-fgr-del]').forEach(b=>b.onclick=()=>{ const a=getFgRateMaster();a.splice(Number(b.dataset.fgrDel),1);saveFgRateMaster(a);renderFgRateMaster(); }); } function setupFgRateItemSuggest(){ const input=$('fgRateItem'),box=$('fgRateItemSuggest');if(!input||!box)return; const show=()=>{ const q=input.value.trim().toLowerCase();box.innerHTML=''; if(!q){box.style.display='none';return} getFinishedGoodsForRate().filter(i=>String(i.name||'').toLowerCase().includes(q)||String(i.code||'').toLowerCase().includes(q)).slice(0,12).forEach(i=>{ const d=document.createElement('div'); d.textContent=String(i.name||'')+' — '+String(i.code||''); d.style.cssText='padding:10px 12px;background:#fff;color:#111;border-bottom:1px solid #ddd;cursor:pointer'; d.onmousedown=e=>{e.preventDefault();input.value=String(i.name||'');input.dataset.selectedCode=String(i.code||'');box.style.display='none'}; box.appendChild(d); }); box.style.display=box.children.length?'block':'none'; }; input.addEventListener('input',show);input.addEventListener('focus',show);input.addEventListener('keyup',show); document.addEventListener('click',e=>{if(e.target!==input&&!box.contains(e.target))box.style.display='none'}); } function addFgRateMaster(){ const input=String($('fgRateItem')?.value||'').trim(); const code=String($('fgRateItem')?.dataset.selectedCode||'').trim(); const rate=Number($('fgRateValue')?.value); const item=getFinishedGoodsForRate().find(i=>String(i.code||'')===code)||getFinishedGoodsForRate().find(i=>String(i.name||'').toLowerCase()===input.toLowerCase()); if(!item){alert('Finished Good Item Masterમાંથી select કરો.');return} if(!Number.isFinite(rate)||rate<0){alert('Valid Rate નાખો.');return} const a=getFgRateMaster(); const old=a.find(x=>String(x.itemCode||'')===String(item.code||'')); if(old){old.itemName=item.name;old.rate=rate} else a.push({itemCode:item.code,itemName:item.name,rate}); saveFgRateMaster(a);renderFgRateMaster(); $('fgRateItem').value='';$('fgRateItem').dataset.selectedCode='';$('fgRateValue').value=''; if($('fgRateMsg'))$('fgRateMsg').textContent='Finished Goods rate saved.'; } function renderDispatchEntries(){ const body=$('dispatchTable')?.querySelector('tbody');if(!body)return; const rows=(transactions||[]).filter(t=>String(t.type||'').toUpperCase()==='DISPATCH').slice().reverse(); body.innerHTML=rows.map((t,n)=>{ const it=items.find(i=>String(i.code||'')===String(t.item||'')),q=Math.abs(Number(t.qty)||0),r=Number(t.dispatchRate||0),tr=Number(t.taxRate||0),tax=Number(t.tax??q*r*tr/100),a=Number(t.amount??q*r),g=Number(t.grandTotal??a+tax); return `${t.date||''}${t.billNo||''}${t.customer||''}${it?it.name:(t.itemName||t.item||'')}${q.toFixed(3)}₹${r.toFixed(2)}₹${a.toFixed(2)}${tr.toFixed(2)}%₹${tax.toFixed(2)}₹${g.toFixed(2)}${t.remark||''} `; }).join('')||'No dispatch entries'; document.querySelectorAll('[data-dispatch-edit]').forEach(b=>b.onclick=()=>{ const t=(transactions||[]).find((x,n)=>String(x.id||n)===String(b.dataset.dispatchEdit));if(!t)return; const it=items.find(i=>String(i.code||'')===String(t.item||'')); const currentDate=(t.date||'').slice(0,10); const newDate=prompt('Dispatch Date (YYYY-MM-DD):',/^\d{4}-\d{2}-\d{2}$/.test(currentDate)?currentDate:new Date().toISOString().slice(0,10));if(newDate===null)return; const newCustomer=prompt('Customer:',t.customer||'');if(newCustomer===null)return; const newQty=Number(prompt('Quantity:',Math.abs(Number(t.qty)||0)));if(!Number.isFinite(newQty)||newQty<=0)return alert('Valid Quantity નાખો.'); const newRate=Number(prompt('Rate:',Number(t.dispatchRate||0)));if(!Number.isFinite(newRate)||newRate<0)return alert('Valid Rate નાખો.'); const newTaxRate=Number(prompt('GST %:',Number(t.taxRate||0)));if(!Number.isFinite(newTaxRate)||newTaxRate<0)return alert('Valid GST % નાખો.'); const newRemark=prompt('Remark:',t.remark||'');if(newRemark===null)return; if(!newCustomer||!it)return alert('Customer અથવા Finished Good મળ્યું નથી.'); const oldQty=Math.abs(Number(t.qty)||0); const available=Number(it.stock||0)+oldQty; if(newQty>available)return alert('Insufficient stock. Available for edit: '+available.toFixed(3)+' '+(it.unit||'')); it.stock=available-newQty; const amount=newQty*newRate,tax=amount*newTaxRate/100; t.date=newDate;t.customer=newCustomer;t.qty=-newQty;t.dispatchRate=newRate;t.amount=amount;t.taxRate=newTaxRate;t.tax=tax;t.grandTotal=amount+tax;t.remark=newRemark; save();renderDispatchEntries();msg('dispatchMsg','Dispatch updated successfully.'); }); document.querySelectorAll('[data-dispatch-del]').forEach(b=>b.onclick=()=>{ const t=(transactions||[]).find((x,n)=>String(x.id||n)===String(b.dataset.dispatchDel));if(!t)return; if(!confirm('Delete Dispatch and reverse stock?'))return; const it=items.find(i=>String(i.code||'')===String(t.item||''));if(it)it.stock+=Math.abs(Number(t.qty)||0); const ix=transactions.indexOf(t);if(ix>=0)transactions.splice(ix,1);save();if($('dispatchDate') && !$('dispatchDate').value)$('dispatchDate').value=getSystemDateISO();renderDispatchEntries();renderDispatchCart();showNextDispatchBillNo(); }); } function setupDispatchCustomerSuggest(){ const i=$('dispatchCustomer'),b=$('dispatchCustomerSuggest');if(!i||!b)return; function names(){ try{const a=JSON.parse(localStorage.getItem('adr_customer_master_v1')||'[]');return Array.isArray(a)?a.map(x=>String(x.name||'').trim()).filter(Boolean):[]}catch(e){return[]} } const show=()=>{const q=i.value.trim().toLowerCase();b.innerHTML='';if(!q){b.style.display='none';return}names().filter(n=>n.toLowerCase().includes(q)).slice(0,10).forEach(n=>{const d=document.createElement('div');d.textContent=n;d.style.cssText='padding:10px;background:#fff;border-bottom:1px solid #ddd;cursor:pointer';d.onmousedown=e=>{e.preventDefault();i.value=n;b.style.display='none'};b.appendChild(d)});b.style.display=b.children.length?'block':'none'}; i.addEventListener('input',show);i.addEventListener('focus',show); } function dispatchUpdateAmount(){const q=Number($('dispatchQty')?.value)||0,r=Number($('dispatchRate')?.value)||0,t=Number($('dispatchTaxRate')?.value)||0;const a=q*r,tax=a*t/100;if($('dispatchAmount'))$('dispatchAmount').value=a.toFixed(2);if($('dispatchTaxAmount'))$('dispatchTaxAmount').value=tax.toFixed(2);if($('dispatchGrandTotal'))$('dispatchGrandTotal').value=(a+tax).toFixed(2);} function generateDispatchReport(){ try{ const from=$('dispatchReportFrom')?.value||'',to=$('dispatchReportTo')?.value||''; const customer=($('dispatchReportCustomer')?.value||'').trim().toLowerCase(); const itemQ=($('dispatchReportItem')?.value||'').trim().toLowerCase(); const rows=(transactions||[]).filter(t=>{ if(String(t.type||'').toUpperCase()!=='DISPATCH')return false; const raw=String(t.date||'');let d=''; let m=raw.match(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/); if(m)d=m[3]+'-'+String(m[2]).padStart(2,'0')+'-'+String(m[1]).padStart(2,'0'); else{const dt=new Date(raw);if(!isNaN(dt))d=dt.toISOString().slice(0,10)} const c=String(t.customer||'').toLowerCase(); const it=items.find(i=>String(i.code||'')===String(t.item||'')); const n=String(it?.name||t.itemName||t.item||'').toLowerCase(); return (!from||d>=from)&&(!to||d<=to)&&(!customer||c.includes(customer))&&(!itemQ||n.includes(itemQ)); }); let qty=0,amount=0,rowsHtml=''; rows.slice().reverse().forEach(t=>{ const it=items.find(i=>String(i.code||'')===String(t.item||'')); const q=Math.abs(Number(t.qty)||0),r=Number(t.dispatchRate||0),a=Number(t.amount??q*r); qty+=q;amount+=a; rowsHtml+=`${t.billNo||''}${t.date||''}${t.customer||''}${it?.name||t.itemName||t.item||''}${q.toFixed(3)}₹${r.toFixed(2)}₹${a.toFixed(2)}${t.remark||''}`; }); $('dispatchReportTable').querySelector('tbody').innerHTML=rowsHtml||'No dispatch entries found'; $('dispatchReportQty').textContent=qty.toFixed(3); $('dispatchReportAmount').textContent='₹'+amount.toFixed(2); $('dispatchReportMsg').textContent=rows.length+' dispatch entries found.'; }catch(e){if($('dispatchReportMsg'))$('dispatchReportMsg').textContent='Report error: '+e.message;} } function setupDispatchReportSuggestions(){ const ci=$('dispatchReportCustomer'),cb=$('dispatchReportCustomerSuggest'); if(ci&&cb)ci.addEventListener('input',()=>{ const q=ci.value.toLowerCase().trim();cb.innerHTML=''; if(!q){cb.style.display='none';return} let a=[];try{a=JSON.parse(localStorage.getItem('adr_customer_master_v1')||'[]')}catch(e){} [...new Set(a.map(x=>String(x.name||'').trim()).filter(Boolean))].filter(n=>n.toLowerCase().includes(q)).slice(0,10).forEach(n=>{ const d=document.createElement('div');d.textContent=n;d.style.cssText='padding:10px;background:#fff;border-bottom:1px solid #ddd;cursor:pointer';d.onmousedown=e=>{e.preventDefault();ci.value=n;cb.style.display='none'};cb.appendChild(d); });cb.style.display=cb.children.length?'block':'none'; }); const ii=$('dispatchReportItem'),ib=$('dispatchReportItemSuggest'); if(ii&&ib)ii.addEventListener('input',()=>{ const q=ii.value.toLowerCase().trim();ib.innerHTML=''; if(!q){ib.style.display='none';return} (items||[]).filter(x=>String(x.cat||'')==='Finished Goods'&&(String(x.name||'').toLowerCase().includes(q)||String(x.code||'').toLowerCase().includes(q))).slice(0,10).forEach(x=>{ const d=document.createElement('div');d.textContent=x.name+' — '+x.code;d.style.cssText='padding:10px;background:#fff;border-bottom:1px solid #ddd;cursor:pointer';d.onmousedown=e=>{e.preventDefault();ii.value=x.name;ib.style.display='none'};ib.appendChild(d); });ib.style.display=ib.children.length?'block':'none'; }); } function generateDispatchMainReport(){ try{ const from=$('dispatchReportFromMain')?.value||'',to=$('dispatchReportToMain')?.value||''; const cq=($('dispatchReportCustomerMain')?.value||'').trim().toLowerCase(); const iq=($('dispatchReportItemMain')?.value||'').trim().toLowerCase(); const toISO=v=>{ const s=String(v||'').trim();let m=s.match(/^(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/); if(m){const a=+m[1],b=+m[2],y=m[3],mm=a>12?b:a,dd=a>12?a:b;return y+'-'+String(mm).padStart(2,'0')+'-'+String(dd).padStart(2,'0')} m=s.match(/^(\d{4})[\/\-](\d{1,2})[\/\-](\d{1,2})/);return m?m[1]+'-'+String(m[2]).padStart(2,'0')+'-'+String(m[3]).padStart(2,'0'):''; }; const rows=(transactions||[]).filter(t=>{ if(String(t.type||'').toUpperCase()!=='DISPATCH')return false; const d=toISO(t.date||t.createdAt||t.timestamp),c=String(t.customer||'').toLowerCase(); const it=(items||[]).find(x=>String(x.code||'')===String(t.item||'')),n=String(it?.name||t.itemName||t.item||'').toLowerCase(); return (!from||!d||d>=from)&&(!to||!d||d<=to)&&(!cq||c.includes(cq))&&(!iq||n.includes(iq)); }); let q=0,a=0,s=''; rows.slice().reverse().forEach(t=>{ const it=(items||[]).find(x=>String(x.code||'')===String(t.item||'')),n=Math.abs(Number(t.qty)||0),r=Number(t.dispatchRate||0),amt=Number(t.amount??n*r);q+=n;a+=amt; const reportDate=toISO(t.date||t.createdAt||t.timestamp)||String(t.date||''); s+=`${t.billNo||''}${reportDate}${t.customer||''}${it?.name||t.itemName||t.item||''}${n.toFixed(3)}₹${r.toFixed(2)}₹${amt.toFixed(2)}${t.remark||''}`; }); $('dispatchReportMainTable').querySelector('tbody').innerHTML=s||'No dispatch entries found'; $('dispatchReportMainQty').textContent=q.toFixed(3);$('dispatchReportMainAmount').textContent='₹'+a.toFixed(2); $('dispatchReportMainMsg').textContent=rows.length+' dispatch entries found.'; }catch(e){if($('dispatchReportMainMsg'))$('dispatchReportMainMsg').textContent='Report error: '+e.message;} } function setupDispatchMainReportSuggestions(){ const ci=$('dispatchReportCustomerMain'),cb=$('dispatchReportCustomerMainSuggest'); if(ci&&cb){ ci.addEventListener('input',()=>{ const q=ci.value.trim().toLowerCase();cb.innerHTML=''; if(!q){cb.style.display='none';return} let a=[];try{a=JSON.parse(localStorage.getItem('adr_customer_master_v1')||'[]')}catch(e){} [...new Set(a.map(x=>String(x.name||'').trim()).filter(Boolean))] .filter(n=>n.toLowerCase().includes(q)).slice(0,12).forEach(n=>{ const d=document.createElement('div');d.textContent=n; d.style.cssText='padding:10px 12px;background:#fff;color:#111;border-bottom:1px solid #ddd;cursor:pointer'; d.onmousedown=e=>{e.preventDefault();ci.value=n;cb.style.display='none'}; cb.appendChild(d); }); cb.style.display=cb.children.length?'block':'none'; }); } const ii=$('dispatchReportItemMain'),ib=$('dispatchReportItemMainSuggest'); if(ii&&ib){ const show=()=>{ const q=ii.value.trim().toLowerCase();ib.innerHTML=''; if(!q){ib.style.display='none';return} (items||[]).filter(x=>{ const cat=String(x.cat||'').toLowerCase(); return cat==='finished goods' && (String(x.name||'').toLowerCase().includes(q)||String(x.code||'').toLowerCase().includes(q)); }).slice(0,12).forEach(x=>{ const d=document.createElement('div');d.textContent=String(x.name||'')+' — '+String(x.code||''); d.style.cssText='padding:10px 12px;background:#fff;color:#111;border-bottom:1px solid #ddd;cursor:pointer'; d.onmousedown=e=>{e.preventDefault();ii.value=String(x.name||'');ii.dataset.selectedCode=String(x.code||'');ib.style.display='none'}; ib.appendChild(d); }); ib.style.display=ib.children.length?'block':'none'; }; ii.addEventListener('input',show);ii.addEventListener('focus',show); } } function setupDispatchReportClearButtons(){ const c=$('clearDispatchReportCustomer'),ci=$('dispatchReportCustomerMain'); const i=$('clearDispatchReportItem'),ii=$('dispatchReportItemMain'); if(c&&ci)c.onclick=()=>{ci.value='';ci.dataset.selectedCode='';ci.focus();}; if(i&&ii)i.onclick=()=>{ii.value='';ii.dataset.selectedCode='';ii.focus();}; } function setupAllReportClearButtons(){ const fields=[ 'purchaseReportSupplier','prodReportProduct','productionReportProduct', 'purchaseReportFrom','purchaseReportTo','productionReportFrom','productionReportTo' ]; fields.forEach(id=>{ const b=$('clear_'+id),el=$(id); if(b&&el)b.onclick=()=>{el.value='';if(el.dataset)el.dataset.selectedCode='';el.focus();}; }); } function getAccountingPayments(){ try{const a=JSON.parse(localStorage.getItem('adr_accounting_payments_v1')||'[]');return Array.isArray(a)?a:[]}catch(e){return[]} } function saveAccountingPayments(a){localStorage.setItem('adr_accounting_payments_v1',JSON.stringify(a));} function accountingBillValues(t){ const net=Number( t.grandTotal ?? t.billTotal ?? t.total ?? t.netAmount ?? t.amount ?? ((Number(t.qty)||0)*(Number(t.purchaseRate ?? t.rate ?? 0))) ) || 0; const gst=Number( t.gst ?? t.tax ?? t.gstAmount ?? t.taxAmount ?? ((net * Number(t.taxRate ?? t.gstRate ?? 0))/100) ) || 0; // For purchase/inward entries, `amount` is generally the taxable/net amount. // If an explicit GST exists, bill amount must be net + GST. const type=String(t.type||t.transactionType||'').toUpperCase(); const isPurchase=/PURCHASE|INWARD/.test(type); let taxable=Number(t.amount ?? t.taxableAmount ?? t.netAmount); if(!Number.isFinite(taxable)) taxable=net; let bill=Number(t.grandTotal ?? t.billTotal ?? t.total); if(!Number.isFinite(bill) || bill===0){ bill=isPurchase ? taxable+gst : net; } // If stored grandTotal is actually only net on older purchase rows, correct it. if(isPurchase && gst>0 && Math.abs(bill-taxable)<0.005) bill=taxable+gst; return {taxable, gst, bill}; } function renderAccounting(){ const customer='',itemQ=''; const sales=(transactions||[]).filter(t=>{if(String(t.type||'').toUpperCase()!=='DISPATCH')return false;const it=(items||[]).find(i=>String(i.code||'')===String(t.item||''));return (!customer||String(t.customer||'').toLowerCase().includes(customer))&&(!itemQ||String(it?.name||t.itemName||t.item||'').toLowerCase().includes(itemQ));}); const payments=getAccountingPayments().filter(p=>!customer||String(p.customer||'').toLowerCase().includes(customer)); let tax=0,grand=0,received=0,rows=''; sales.forEach(t=>{const it=(items||[]).find(i=>String(i.code||'')===String(t.item||'')),q=Math.abs(Number(t.qty)||0),bv=accountingBillValues(t),a=Number(bv.taxable)||0,x=Number(bv.gst)||0,g=Number(bv.bill)||0;tax+=x;grand+=g;rows+=`${t.date||''}Sales${t.customer||''}${t.billNo||t.ref||''}${it?.name||t.itemName||t.item||''}${q.toFixed(3)}₹${a.toFixed(2)}₹${x.toFixed(2)}₹${g.toFixed(2)}${t.remark||''}`}); payments.forEach(p=>{const a=Number(p.amount)||0;received+=a;rows+=`${p.date||''}Payment${p.customer||''}${p.ref||''}₹${a.toFixed(2)}${p.mode||''}${p.remark||''}`}); $('accSales').textContent='₹'+grand.toFixed(2);$('accTax').textContent='₹'+tax.toFixed(2);$('accReceived').textContent='₹'+received.toFixed(2);$('accDue').textContent='₹'+(grand-received).toFixed(2);$('accTable').querySelector('tbody').innerHTML=rows||'No accounting entries';;renderCustomerDueSummary();renderPartyLedgers();renderMergedPartyLedger() } function saveAccountingPayment(){ const customer=String($('accPaymentCustomer')?.value||'').trim(),amount=Number($('accPaymentAmount')?.value)||0; if(!customer||amount<=0){alert('Payment Customer અને valid Payment Amount નાખો.');return} const a=getAccountingPayments(); a.push({date:$('accPaymentDate').value||new Date().toLocaleDateString('en-GB'),customer,amount,mode:$('accPaymentMode').value,ref:$('accPaymentRef').value.trim(),remark:$('accPaymentRef').value.trim()}); saveAccountingPayments(a); $('accPaymentAmount').value='';$('accPaymentRef').value=''; renderAccounting(); if($('accMsg'))$('accMsg').textContent='Payment saved.'; } function setupAccountingPaymentButtonsV133(){ const r=$('openReceivePaymentBtn'),p=$('openPaySupplierBtn'),rs=$('receivePaymentSection'),ps=$('paySupplierSection'); if(!r||!p||!rs||!ps)return; // V215 owns these click handlers so each submenu toggles its own fields. } function setupAccountingCustomerSuggest(){ const i=$('accCustomer'),b=$('accCustomerSuggest');if(!i||!b)return; const show=()=>{const q=i.value.toLowerCase().trim();b.innerHTML='';if(!q){b.style.display='none';renderAccounting();return}let a=[];try{a=JSON.parse(localStorage.getItem('adr_customer_master_v1')||'[]')}catch(e){}[...new Set(a.map(x=>String(x.name||'').trim()).filter(Boolean))].filter(n=>n.toLowerCase().includes(q)).slice(0,12).forEach(n=>{const d=document.createElement('div');d.textContent=n;d.style.cssText='padding:10px;background:#fff;border-bottom:1px solid #ddd;cursor:pointer';d.onmousedown=e=>{e.preventDefault();i.value=n;b.style.display='none';renderAccounting()};b.appendChild(d)});b.style.display=b.children.length?'block':'none'}; i.addEventListener('input',show);i.addEventListener('focus',show); } function setupDispatchClearButtonsV83(){ const c=$('clearDispatchCustomer'),ci=$('dispatchCustomer'); const i=$('clearDispatchItem'),ii=$('dispatchCode'); if(c&&ci)c.onclick=()=>{ci.value='';ci.dataset.selectedCode='';ci.focus();}; if(i&&ii)i.onclick=()=>{ii.value='';ii.dataset.selectedCode='';ii.focus();if($('dispatchRate'))$('dispatchRate').value='';dispatchUpdateAmount();}; } function setupAccountingItemSuggest(){const i=$('accItem'),b=$('accItemSuggest');if(!i||!b)return;const show=()=>{const q=i.value.trim().toLowerCase();b.innerHTML='';if(!q){b.style.display='none';renderAccounting();return}(items||[]).filter(x=>String(x.cat||'').toLowerCase()==='finished goods'&&(String(x.name||'').toLowerCase().includes(q)||String(x.code||'').toLowerCase().includes(q))).slice(0,15).forEach(x=>{const d=document.createElement('div');d.textContent=x.name+' — '+x.code;d.style.cssText='padding:10px;background:#fff;border-bottom:1px solid #ddd;cursor:pointer';d.onmousedown=e=>{e.preventDefault();i.value=x.name;b.style.display='none';renderAccounting()};b.appendChild(d)});b.style.display=b.children.length?'block':'none'};i.addEventListener('input',show);i.addEventListener('focus',show)} function setupAccountingClearFilters(){const b=$('accClearFilters');if(b)b.onclick=()=>{$('accCustomer').value='';$('accItem').value='';renderAccounting()}} function setupAccountingPaymentCustomerSuggest(){ const i=$('accPaymentCustomer'),b=$('accPaymentCustomerSuggest');if(!i||!b)return; const show=()=>{ const q=i.value.trim().toLowerCase();b.innerHTML=''; let a=[];try{a=JSON.parse(localStorage.getItem('adr_customer_master_v1')||'[]')}catch(e){} const names=[...new Set(a.map(x=>String(x.name||'').trim()).filter(Boolean))].filter(n=>!q||n.toLowerCase().includes(q)).slice(0,15); names.forEach(n=>{const d=document.createElement('div');d.textContent=n;d.style.cssText='padding:10px;background:#fff;border-bottom:1px solid #ddd;cursor:pointer';d.onmousedown=e=>{e.preventDefault();i.value=n;b.style.display='none'};b.appendChild(d)}); b.style.display=names.length?'block':'none'; }; i.addEventListener('input',show);i.addEventListener('focus',show);i.addEventListener('click',show); } function renderCustomerDueSummary(){ const map={}; const ensure=c=>{if(c&&!map[c])map[c]={sales:0,tax:0,grand:0,received:0}}; const isReturn=t=>{ const type=String(t.type||'').toUpperCase(); return type==='SALES RETURN'||type==='RETURN'||type==='CUSTOMER RETURN'||type==='DISPATCH RETURN' || t.isReturn===true || String(t.entryType||'').toUpperCase()==='RETURN'; }; (transactions||[]).forEach(t=>{ const type=String(t.type||'').toUpperCase(); if(type!=='DISPATCH'&&!isReturn(t))return; const c=String(t.customer||'').trim();if(!c)return; ensure(c); const q=Math.abs(Number(t.qty)||0),r=Number(t.dispatchRate||t.rate||0); const rawA=Number(t.amount),rawTax=Number(t.tax),rawG=Number(t.grandTotal); const a=Number.isFinite(rawA)?rawA:q*r; const tax=Number.isFinite(rawTax)?rawTax:a*(Number(t.taxRate)||0)/100; const grand=Number.isFinite(rawG)?rawG:a+tax; const sign=isReturn(t)?-1:1; map[c].sales+=sign*a;map[c].tax+=sign*tax;map[c].grand+=sign*grand; }); getAccountingPayments().forEach(p=>{ const c=String(p.customer||'').trim();if(!c)return; ensure(c);map[c].received+=Number(p.amount)||0; }); const rows=Object.entries(map).sort((a,b)=>a[0].localeCompare(b[0])).map(([c,v])=>{ const due=v.grand-v.received; return `${c}₹${v.sales.toFixed(2)}₹${v.tax.toFixed(2)}₹${v.grand.toFixed(2)}₹${v.received.toFixed(2)}₹${Math.abs(due).toFixed(2)} ${due>0?'Dr':due<0?'Cr':'-'}`; }).join(''); $('customerDueTable').querySelector('tbody').innerHTML=rows||'No customer data'; } function setupAccountingPaymentClear(){ const b=$('clearAccPayment');if(!b)return; b.onclick=()=>{ $('accPaymentCustomer').value=''; $('accPaymentAmount').value=''; $('accPaymentDate').value='';setupAccountingCustomerAndDateV94();setPaymentDateToday();renderPartyLedgers();setupPartyLedgerFiltersV86();setupSupplierPaymentV87();setupMergedPartyLedgerV87();renderMergedPartyLedger(); $('accPaymentMode').selectedIndex=0; $('accPaymentRef').value=''; if($('accPaymentCustomerSuggest'))$('accPaymentCustomerSuggest').style.display='none'; if($('accMsg'))$('accMsg').textContent=''; }; } function renderCustomerDueSummary(){ const selected=String($('dueCustomerFilter')?.value||'').trim().toLowerCase(); const sales=(transactions||[]).filter(t=>String(t.type||'').toUpperCase()==='DISPATCH' && (!selected||String(t.customer||'').toLowerCase().includes(selected))); const payments=getAccountingPayments().filter(p=>!selected||String(p.customer||'').toLowerCase().includes(selected)); let taxable=0,tax=0,grand=0,received=0,rows=''; sales.forEach(t=>{ const it=(items||[]).find(i=>String(i.code||'')===String(t.item||'')),a=Number(t.amount??(Math.abs(Number(t.qty)||0)*Number(t.dispatchRate||0)))||0,x=Number(t.tax||0)||0,g=Number(t.grandTotal??a+x)||0; taxable+=a;tax+=x;grand+=g; rows+=`${t.date||''}Sales${t.customer||''}${t.billNo||''}${it?.name||t.itemName||t.item||''}₹${a.toFixed(2)}₹${x.toFixed(2)}₹${g.toFixed(2)}${t.remark||''}`; }); payments.forEach(p=>{ const a=Number(p.amount)||0;received+=a; rows+=`${p.date||''}Payment${p.customer||''}${p.ref||''}₹${a.toFixed(2)}${p.mode||''}${p.remark||''}`; }); $('customerDueTable').querySelector('tbody').innerHTML=rows||'No ledger entries found'; $('dueLedgerTaxable').textContent='₹'+taxable.toFixed(2);$('dueLedgerTax').textContent='₹'+tax.toFixed(2);$('dueLedgerGrand').textContent='₹'+grand.toFixed(2);$('dueLedgerPayment').innerHTML='₹'+received.toFixed(2)+'';const dueBal=grand-received;$('dueLedgerDue').innerHTML='Due: ₹'+dueBal.toFixed(2)+''; } function setupDueCustomerFilter(){ const i=$('dueCustomerFilter'),b=$('dueCustomerFilterSuggest');if(!i||!b)return; const show=()=>{ const q=i.value.trim().toLowerCase();b.innerHTML=''; let a=[];try{a=JSON.parse(localStorage.getItem('adr_customer_master_v1')||'[]')}catch(e){} const names=[...new Set(a.map(x=>String(x.name||'').trim()).filter(Boolean))].filter(n=>!q||n.toLowerCase().includes(q)).slice(0,15); names.forEach(n=>{const d=document.createElement('div');d.textContent=n;d.style.cssText='padding:10px;background:#fff;border-bottom:1px solid #ddd;cursor:pointer';d.onmousedown=e=>{e.preventDefault();i.value=n;b.style.display='none';renderCustomerDueSummary()};b.appendChild(d)}); b.style.display=names.length?'block':'none'; }; i.addEventListener('input',show);i.addEventListener('focus',show);i.addEventListener('click',show); const c=$('clearDueCustomerFilter');if(c)c.onclick=()=>{i.value='';b.style.display='none';renderCustomerDueSummary();}; } function downloadCustomerLedgerPDF(){ const selected=String($('dueCustomerFilter')?.value||'').trim(); if(!selected)return alert('પહેલા Customer select કરો.'); const table=$('customerDueTable'); if(!table)return; const win=window.open('','_blank'); if(!win)return alert('PDF માટે popup allow કરો.'); const rows=table.querySelector('tbody')?.innerHTML||''; const foot=table.querySelector('tfoot')?.innerHTML||''; win.document.write(`Customer Ledger - ${selected}

Customer Ledger

Customer: ${selected}

${table.querySelector('thead')?.innerHTML||''}${rows}${foot}