ONE CALL Financial Services

Client Intelligence CRM Portal

Login As
❌ Invalid username or password. Please try again.

Dashboard

RM-wise SIP Performance
City-wise Clients
Recent Clients
Quick Alerts

Client Master

Client 360° View

Add Client

🔔 Alerts Center

Auto-calculated from uploaded data

📊 Reports

Click on any row to drill down into client list

📈 Analytics

Click bars to filter · Click rows to view 360°

✉️ Email Templates

Select template → select client → Outlook opens with pre-filled email

📑 Valuation Report

Upload report → D column client name match → preview → single or all-client email

No report uploaded. Client name D column mein hona chahiye.
Client ke saamne Preview button click karein.

🚀 New Fund Launch

Fill details → Live preview → Send via Outlook

Fund Details
Live Preview
Fill details to see preview

📥 Export Data

📤 Import Data

Naya Excel data upload karo — purana data replace ho jayega. Sirf Admin ke liye.

Step 1 — LIVE SIP WISE DATE file (.xls)
Sheet "MUTUAL FUNDS" wali file — Investor, PAN NO, Scheme, Monthly SIP Amount, Start/End Date columns honi chahiye
Step 2 — FOLIO WISE LIST file (.xls)
Sheet1 wali file — AMC, Folio No, Investor Name, First Holder PAN, Address, Bank columns honi chahiye
Step 3 — Import karo
Note: Import kiya hua data is browser mein save hota hai (localStorage). Health Insurance data built-in hi rahega jab tak uski alag file upload na ho. Import ke baad page khud reload hoga.

💼 Product Wise Investment

Client-wise Mutual Fund, Term Insurance, Health Insurance and other investment/product details

📎 Uploaded Documents View

All uploaded PAN, Aadhaar, Account Opening, Cheque and Other documents

📝 Product Entry Module

Add SIP, Health Insurance, Term Insurance and other product entries manually

🤝 Client Engagement

Meeting notes, client discussion, purpose and next follow-up

✅ My Tasks & Daily Work

Assigned work, progress, pending reasons and daily work report

🔐 User Management

');} else {w.document.write(''+escHtml(d.name)+'');} w.document.close(); } }else alert('Old entry me file preview available nahi hai. Please upload again.'); } function delClientDoc(id,idx){ if(!confirm('Delete this document entry?'))return; var o=getDocStore(); if(o[id]){o[id].splice(idx,1); setDocStore(o);} if(T('pg-documents') && T('pg-documents').classList.contains('on')) renderDocumentsTab(); else view360(id,'360'); } function renderProductWiseInvestment(id,cF,cS,cI){ var act=cS.filter(function(x){return x.status==='Active';}); var mfMonthly=act.reduce(function(a,x){return a+(Number(x.sipAmount)||0);},0); var insTotal=cI.reduce(function(a,x){return a+(Number(x.premium)||0);},0); var rows=[]; if(cF.length||cS.length){ rows.push({product:'Mutual Fund',count:cF.length+' Folios / '+act.length+' Active SIP',amt:mfMonthly,sub:'Monthly SIP Investment',tag:'MF',cls:'bl'}); } var term=cI.filter(function(x){return String(x.type||x.policy||'').toLowerCase().indexOf('term')>=0;}); var health=cI.filter(function(x){return String(x.type||x.policy||'').toLowerCase().indexOf('term')<0;}); if(term.length){rows.push({product:'Term Insurance',count:term.length+' Policies',amt:term.reduce(function(a,x){return a+(Number(x.premium)||0);},0),sub:'Cover / Premium Value',tag:'Term',cls:'vi'});} if(health.length){rows.push({product:'Health Insurance',count:health.length+' Policies',amt:health.reduce(function(a,x){return a+(Number(x.premium)||0);},0),sub:'Cover / Premium Value',tag:'Health',cls:'pi'});} if(!rows.length){ rows.push({product:'No Product',count:'0 Records',amt:0,sub:'No investment/product found',tag:'Pending',cls:'rd'}); } var total=rows.reduce(function(a,x){return a+(Number(x.amt)||0);},0); var html='
'+ '
💼 Product Wise Investment
'+bd(rows.length+' Products','gr')+'
'+ '
'; rows.forEach(function(r){ var pct=total>0?Math.round((r.amt/total)*100):0; html+=''; }); html+='
ProductInvestment / ValueRecordsDetails
'+bd(r.tag,r.cls)+' '+r.product+''+fmt(r.amt)+'
'+r.sub+'
'+r.count+'
'+pct+'% of total visible value
'; return html; } function renderClientDocuments(id){ var docs=getClientDocs(id); var html='
📎 Client Documents Upload
'+ '
'+ '
'+ '
'+ '
'+ ''+ '
'; if(docs.length){ html+='
'; docs.forEach(function(d,i){ html+=''; }); html+='
TypeDocument NameFile NameUploaded OnViewAction
'+docIcon(d.type)+' '+escHtml(d.type)+''+escHtml(d.name)+''+escHtml(d.file)+'
'+Math.round((d.size||0)/1024)+' KB
'+escHtml(d.date)+'
'; }else{ html+='
No document uploaded. Upload PAN, Aadhaar, Account Opening Document, Cheque or Other Document here.
'; } html+='
'; return html; } // ════════════════════════════════════════════════ // MANUAL PRODUCT ENTRY MODULE + EXCEL DOWNLOAD // ════════════════════════════════════════════════ let editPEId = null; function getPEStore(){try{return JSON.parse(localStorage.getItem('ONECALL_PRODUCT_ENTRIES')||'[]');}catch(e){return [];}} function setPEStore(a){localStorage.setItem('ONECALL_PRODUCT_ENTRIES',JSON.stringify(a||[]));} function allProductEntries(){return getPEStore();} function clientById(id){return CLIENTS.filter(function(c){return String(c.id)===String(id);})[0]||{};} function productBaseRows(){ var cl=visCL(), ids=new Set(cl.map(function(c){return c.id;})), rows=[]; SIPS.filter(function(s){return ids.has(s.clientId);}).forEach(function(s){var c=clientById(s.clientId);rows.push({id:'SIP_'+s.clientId+'_'+(s.folio||''),source:'System',clientId:s.clientId,client:c.name||'',pan:c.pan||'',mobile:c.mobile||'',rm:c.rm||'',product:'Mutual Fund SIP',scheme:s.scheme||'',folio:s.folio||'',amount:Number(s.sipAmount)||0,frequency:'Monthly',startDate:s.startDate||'',endDate:s.endDate||'',status:s.status||'',notes:''});}); INSURANCE.filter(function(i){return ids.has(i.clientId);}).forEach(function(i){var c=clientById(i.clientId);var isTerm=String(i.type||i.policy||'').toLowerCase().indexOf('term')>=0;rows.push({id:'INS_'+i.clientId+'_'+(i.policyNo||''),source:'System',clientId:i.clientId,client:c.name||'',pan:c.pan||'',mobile:c.mobile||'',rm:c.rm||i.rm||'',product:isTerm?'Term Insurance':'Health Insurance',scheme:i.policy||'',folio:i.policyNo||'',amount:Number(i.premium)||0,frequency:'Yearly',startDate:'',endDate:i.renewalDate||'',status:'Active',notes:''});}); return rows; } function manualProductRows(){ var ids=new Set(visCL().map(function(c){return c.id;})); return getPEStore().filter(function(e){return ids.has(Number(e.clientId));}).map(function(e){var c=clientById(e.clientId);return Object.assign({},e,{source:'Manual',client:c.name||e.client||'',pan:c.pan||e.pan||'',mobile:c.mobile||'',rm:c.rm||e.rm||''});}); } function allProductRows(){return productBaseRows().concat(manualProductRows());} function showProductEntryForm(edit,id){ var e={}; editPEId=null; if(edit){var a=getPEStore(); e=a.filter(function(x){return String(x.id)===String(id);})[0]||{}; editPEId=e.id;} var opts=visCL().map(function(c){return '';}).join(''); T('peFormCard').style.display='block'; T('peFormCard').innerHTML='
'+(edit?'Edit':'Add')+' Product Entry
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'; } function saveProductEntry(){ var cid=Number(T('pe_clientId').value), c=clientById(cid), a=getPEStore(); var e={id:editPEId||Date.now(),clientId:cid,client:c.name||'',pan:c.pan||'',rm:c.rm||'',product:T('pe_product').value,scheme:T('pe_scheme').value,folio:T('pe_folio').value,amount:Number(T('pe_amount').value)||0,frequency:T('pe_frequency').value,startDate:T('pe_startDate').value,endDate:T('pe_endDate').value,status:T('pe_status').value,notes:T('pe_notes').value,updatedOn:new Date().toLocaleString('en-IN')}; if(editPEId){for(var i=0;i=0;}); var total=rows.reduce(function(a,r){return a+(Number(r.amount)||0);},0), active=rows.filter(function(r){return r.status==='Active';}).length; T('peKpi').innerHTML=[['Manual Entries',rows.length,'#1B4FD8'],['Active',active,'#16a34a'],['Total Amount',fmt(total),'#7C3AED'],['Clients',new Set(rows.map(function(r){return r.clientId;})).size,'#EC4899']].map(function(k){return '
'+k[0]+'
'+k[1]+'
';}).join(''); var html='ClientPANProductScheme / PolicyFolio / Policy NoAmountFrequencyDateStatusAction'; rows.forEach(function(r){html+=''+escHtml(r.client)+'
'+escHtml(r.rm||'')+'
'+escHtml(r.pan||'')+''+bd(escHtml(r.product||''),'bl')+''+escHtml(r.scheme||'')+''+escHtml(r.folio||'')+''+fmt(r.amount)+''+escHtml(r.frequency||'')+''+escHtml((r.startDate||'')+' → '+(r.endDate||''))+''+bd(escHtml(r.status||''),r.status==='Active'?'gr':(r.status==='Expired'?'rd':'am'))+'';}); T('peTbl').innerHTML=html+''; } function renderProductWiseTab(){ var q=(T('pwSrch')?T('pwSrch').value:'').toLowerCase(); var rows=allProductRows().filter(function(r){var t=[r.client,r.pan,r.mobile,r.rm,r.product,r.scheme,r.folio,r.status,r.source].join(' ').toLowerCase();return !q||t.indexOf(q)>=0;}); var total=rows.reduce(function(a,r){return a+(Number(r.amount)||0);},0); var mf=rows.filter(function(r){return String(r.product).toLowerCase().indexOf('mutual')>=0;}).reduce(function(a,r){return a+(Number(r.amount)||0);},0); var health=rows.filter(function(r){return String(r.product).toLowerCase().indexOf('health')>=0;}).reduce(function(a,r){return a+(Number(r.amount)||0);},0); var term=rows.filter(function(r){return String(r.product).toLowerCase().indexOf('term')>=0;}).reduce(function(a,r){return a+(Number(r.amount)||0);},0); T('pwKpi').innerHTML=[['Total Records',rows.length,'#1B4FD8'],['MF SIP',fmt(mf),'#16a34a'],['Health',fmt(health),'#EC4899'],['Term',fmt(term),'#7C3AED']].map(function(k){return '
'+k[0]+'
'+k[1]+'
';}).join(''); var html='ClientPANMobileRMProductScheme / PolicyFolio / Policy NoAmountFrequencyStatusSource'; rows.forEach(function(r){html+=''+escHtml(r.client)+''+escHtml(r.pan||'')+''+escHtml(r.mobile||'')+''+bd(escHtml((r.rm||'').split(' ')[0]),'bl')+''+bd(escHtml(r.product||''),String(r.product).toLowerCase().indexOf('health')>=0?'pi':(String(r.product).toLowerCase().indexOf('term')>=0?'vi':'gr'))+''+escHtml(r.scheme||'')+''+escHtml(r.folio||'')+''+fmt(r.amount)+''+escHtml(r.frequency||'')+''+bd(escHtml(r.status||''),r.status==='Active'?'gr':(r.status==='Expired'?'rd':'am'))+''+escHtml(r.source||'')+'';}); T('pwTbl').innerHTML=html+''; } function tableToExcel(tableId, filename){ var tbl=T(tableId); if(!tbl){alert('No table found.');return;} var html=''+tbl.innerHTML+'
'; var a=document.createElement('a'); a.href=URL.createObjectURL(new Blob([html],{type:'application/vnd.ms-excel'})); a.download=(filename||'onecall_export')+'.xls'; a.click(); } function datasetToExcel(headers,rows,filename){ var html=''+headers.map(function(h){return '';}).join('')+''+rows.map(function(r){return ''+r.map(function(c){return '';}).join('')+'';}).join('')+'
'+escHtml(h)+'
'+escHtml(c)+'
'; var a=document.createElement('a'); a.href=URL.createObjectURL(new Blob([html],{type:'application/vnd.ms-excel'})); a.download=filename+'.xls'; a.click(); } function downloadAllClientsExcel(){ var q=(T('cSrch')?T('cSrch').value:'').trim().toLowerCase(); var clients=visCL().filter(function(c){ var text=[c.name,c.pan,c.mobile,c.email,c.dob,c.city,c.pincode,c.address,c.rm,c.accountStatus,c.docStatus,c.source].join(' ').toLowerCase(); return !q||text.indexOf(q)>=0; }); if(!clients.length){alert('Export ke liye client records nahi mile.');return;} var products=typeof allVisibleProductRows==='function'?allVisibleProductRows():[]; var rows=clients.map(function(c,index){ var cr=products.filter(function(r){return String(r.clientId)===String(c.id);}); var mf=cr.filter(function(r){return typeof ocProductKind==='function'&&ocProductKind(r)==='mf';}).reduce(function(a,r){return a+(Number(r.amount)||0);},0); var health=cr.filter(function(r){return typeof ocProductKind==='function'&&ocProductKind(r)==='health';}).length; var term=cr.filter(function(r){return typeof ocProductKind==='function'&&ocProductKind(r)==='term';}).length; return { 'Sr. No.':index+1,'Client ID':c.id||'','Client Name':c.name||'','PAN':c.pan||'','Mobile':c.mobile||'','Email':c.email||'', 'DOB':c.dob||'','City':c.city||'','Pincode':c.pincode||'','Address':c.address||'','RM Name':c.rm||'', 'Account Status':c.accountStatus||'Account Open','KYC / Document Status':c.docStatus||'Pending','MF SIP Amount':mf, 'Health Records':health,'Term Records':term,'Record Source':c.source||'System','Last Updated':c.updatedOn||'' }; }); var stamp=new Date().toISOString().slice(0,10); if(window.XLSX){ var ws=XLSX.utils.json_to_sheet(rows), wb=XLSX.utils.book_new(); ws['!cols']=[{wch:8},{wch:12},{wch:28},{wch:14},{wch:16},{wch:30},{wch:13},{wch:20},{wch:10},{wch:42},{wch:22},{wch:20},{wch:22},{wch:16},{wch:14},{wch:12},{wch:14},{wch:22}]; XLSX.utils.book_append_sheet(wb,ws,'All Clients'); XLSX.writeFile(wb,'ONECALL_Client_Master_All_'+clients.length+'_Records_'+stamp+'.xlsx'); }else{ var headers=Object.keys(rows[0]), matrix=rows.map(function(r){return headers.map(function(h){return r[h];});}); datasetToExcel(headers,matrix,'ONECALL_Client_Master_All_'+clients.length+'_Records_'+stamp); } alert('✅ '+clients.length+' client records Excel mein download ho gaye.\nCurrent page ke nahi, sabhi matching records export hue hain.'); } function downloadPageExcel(k){ if(k==='clients') return downloadAllClientsExcel(); if(k==='productwise') return tableToExcel('pwTbl','onecall_product_wise_investment'); if(k==='productentry') return tableToExcel('peTbl','onecall_product_entry_manual'); if(k==='documents') return tableToExcel('docTbl','onecall_uploaded_documents'); if(k==='users') return tableToExcel('uTbl','onecall_users'); if(k==='reports') {var t=T('rpContent')&&T('rpContent').querySelector('table'); if(t){t.id='tmpRpTbl'; return tableToExcel('tmpRpTbl','onecall_reports');}} if(k==='alerts') {var t=T('alContent')&&T('alContent').querySelector('table'); if(t){t.id='tmpAlTbl'; return tableToExcel('tmpAlTbl','onecall_alerts');}} if(k==='dashboard') return tableToExcel('dashTbl','onecall_dashboard_recent_clients'); if(k==='analytics') {var t=T('anaContent')&&T('anaContent').querySelector('table'); if(t){t.id='tmpAnaTbl'; return tableToExcel('tmpAnaTbl','onecall_analytics');}} if(k==='export') return doCSV('clients'); alert('Is menu me download ke liye table data available nahi hai.'); } function addDownloadButtonToPage(k){ if(k==='360'||k==='add'||k==='email'||k==='newfund')return; setTimeout(function(){ var pg=T('pg-'+k); if(!pg||pg.querySelector('.auto-xls-btn')||pg.querySelector('[onclick*="downloadPageExcel"]'))return; var ph=pg.querySelector('.ph'); if(!ph)return; var wrap=ph.parentElement; var btn=''; if(wrap&&wrap.style&&wrap.style.display.indexOf('flex')>=0){wrap.insertAdjacentHTML('beforeend',btn);} else {ph.insertAdjacentHTML('afterend','
'+btn+'
');} },0); } // ════════════════════════════════════════════════ // EMAIL HELPERS // ════════════════════════════════════════════════ function fillBody(tmplKey, client) { var tmpl = ETMPLS[tmplKey]; if (!tmpl) return ''; var sip = SIPS.filter(function(s){return s.clientId === client.id && s.status === 'Active';})[0]; return tmpl.body .replace(/\{\{NAME\}\}/g, client.name || 'Valued Client') .replace(/\{\{RM\}\}/g, client.rm || 'your RM') .replace(/\{\{AMT\}\}/g, sip ? (sip.sipAmount||0).toLocaleString('en-IN') : '—') .replace(/\{\{SCHEME\}\}/g, sip ? (sip.scheme || 'your SIP') : 'your SIP') .replace(/\{\{DATE\}\}/g, sip ? (sip.endDate || '—') : '—'); } function buildEP(subject, bodyText, ico) { var lsrc = "data:image/jpeg;base64,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"; return '
' + '
' + '
ONE CALL
' + '
ONE CALL Financial Services
' + '
Client Communication
' + '
' + '
' + '
' + '
' + '
' + (ico||'') + ' ' + subject + '
' + '
' + bodyText.split('\n').join('
') + '
' + '
' + '
' + '
ONE CALL Financial Services
' + '' + '
Mumbai, Maharashtra | info@onecallfinancial.com | +91 98765 43210
' + '
' + '
' + '
'; } function outlookOpen(email, subject, body) { var uri = 'mailto:' + encodeURIComponent(email||'') + '?subject=' + encodeURIComponent(subject) + '&body=' + encodeURIComponent(body); var a = document.createElement('a'); a.href = uri; a.click(); } // ════════════════════════════════════════════════ // LOGIN // ════════════════════════════════════════════════ function setRole(r) { selRole = r; ['admin','rm','emp'].forEach(id => { var el = T('rb_' + id); if (el) el.classList.remove('on'); }); var map = {Admin:'admin', RM:'rm', Employee:'emp'}; var btn = T('rb_' + map[r]); if (btn) btn.classList.add('on'); } function doLogin() { var u = T('lU').value.trim(); var p = T('lP').value.trim(); if (!u || !p) { T('lErr').textContent = 'Please enter username and password.'; T('lErr').style.display = 'block'; return; } var user = null; for (var i = 0; i < USERS.length; i++) { if (USERS[i].u === u && USERS[i].p === p) { user = USERS[i]; break; } } if (!user) { T('lErr').textContent = 'Invalid username or password.'; T('lErr').style.display = 'block'; return; } T('lErr').style.display = 'none'; CU = user; T('LP').style.display = 'none'; T('SB').style.display = 'flex'; T('MN').style.display = 'block'; T('sbNm').textContent = user.name; T('sbRl').textContent = user.role; buildNav(); goPage('dashboard'); } function doLogout() { CU = null; T('LP').style.display = 'flex'; T('SB').style.display = 'none'; T('MN').style.display = 'none'; T('lU').value = ''; T('lP').value = ''; T('lErr').style.display = 'none'; setRole('Admin'); } // ════════════════════════════════════════════════ // NAVIGATION // ════════════════════════════════════════════════ var NAV = [ {k:'dashboard',i:'⊞',l:'Dashboard'}, {k:'clients', i:'👥',l:'Client Master'}, {k:'alerts', i:'🔔',l:'Alerts Center'}, {k:'reports', i:'📊',l:'Reports'}, {k:'productwise',i:'💼',l:'Product Wise Investment'}, {k:'productentry',i:'📝',l:'Product Entry Module'}, {k:'documents',i:'📎',l:'Uploaded Documents'}, {k:'analytics',i:'📈',l:'Analytics'}, {k:'email', i:'✉️', l:'Email Templates'}, {k:'valuation',i:'📑',l:'Valuation Report'}, {k:'newfund', i:'🚀',l:'New Fund Launch'}, {k:'export', i:'📥',l:'Export Data'}, {k:'import', i:'📤',l:'Import Data', admin:true}, {k:'users', i:'🔐',l:'User Management', admin:true}, ]; function buildNav() { var html = ''; for (var i = 0; i < NAV.length; i++) { var n = NAV[i]; if (n.admin && CU.role !== 'Admin') continue; html += '' + '' + n.i + '' + n.l + ''; } T('sbNav').innerHTML = html; } function goPage(k, from) { document.querySelectorAll('.pg').forEach(function(p){p.classList.remove('on');}); document.querySelectorAll('.sbnav a').forEach(function(a){a.classList.remove('on');}); var pg = T('pg-' + k); if (pg) pg.classList.add('on'); var nb = T('nav-' + k); if (nb) nb.classList.add('on'); if (from) backPage = from; if (k === 'dashboard') renderDash(); else if (k === 'clients') renderCT(); else if (k === 'alerts') renderAl(alTab); else if (k === 'reports') renderRp(rpTab); else if (k === 'productwise') renderProductWiseTab(); else if (k === 'productentry') renderProductEntry(); else if (k === 'documents') renderDocumentsTab(); else if (k === 'analytics') renderAna(); else if (k === 'email') renderEmail(); else if (k === 'valuation') renderValuation(); else if (k === 'newfund') nfLive(); else if (k === 'export') renderExp(); else if (k === 'import') renderImport(); else if (k === 'users') renderUsers(); addDownloadButtonToPage(k); } // ════════════════════════════════════════════════ // DASHBOARD // ════════════════════════════════════════════════ function renderDash() { T('dashHi').textContent = 'Dashboard Overview'; T('dashDt').textContent = 'Welcome, ' + CU.name + ' · ' + today.toLocaleDateString('en-IN',{weekday:'long',day:'numeric',month:'long',year:'numeric'}); var cl = visCL(), sips = visSIP(), ins = visINS(); var actS = sips.filter(function(s){return s.status==='Active';}); var totalSIP = actS.reduce(function(a,x){return a+x.sipAmount;},0); var exp7 = actS.filter(function(s){return s.endDate&&daysDiff(s.endDate)>=0&&daysDiff(s.endDate)<=7;}).length; var exp30 = actS.filter(function(s){return s.endDate&&daysDiff(s.endDate)>=0&&daysDiff(s.endDate)<=30;}).length; var expd = sips.filter(function(s){return s.endDate&&daysDiff(s.endDate)<0;}).length; var bdT = cl.filter(function(c){try{var d=new Date(c.dob);return d.getMonth()===today.getMonth()&&d.getDate()===today.getDate();}catch(e){return false;}}).length; var noSIP = cl.filter(function(c){return !actS.some(function(s){return s.clientId===c.id;});}).length; var fols = FOLIOS.filter(function(f){return cl.some(function(c){return c.id===f.clientId;});}); var insR30= ins.filter(function(i){return i.renewalDate&&daysDiff(i.renewalDate)>=0&&daysDiff(i.renewalDate)<=30;}).length; var kpis=[ {l:'Total Clients', v:cl.length, s:'Registered', c:'#0A2463',i:'👥',p:'clients'}, {l:'Monthly SIP Book', v:fmt(totalSIP)+'/mo', s:actS.length+' active SIPs',c:'#1B4FD8',i:'🔄',p:'alerts'}, {l:'Total Folios', v:fols.length, s:'Across all AMCs', c:'#7C3AED',i:'📂',p:'reports'}, {l:'Health Insurance', v:ins.length, s:insR30+' renewal due 30d',c:'#EC4899',i:'🏥',p:'alerts'}, {l:'SIP Expiring (7d)',v:exp7, s:exp30+' in 30d · '+expd+' expired',c:'#EF4444',i:'⚠️',p:'alerts'}, {l:'Birthdays Today', v:bdT, s:'Click to send wishes',c:'#F59E0B',i:'🎂',p:'alerts'}, {l:'Active SIPs', v:actS.length, s:'Running SIPs', c:'#22C55E',i:'✅',p:'clients'}, {l:'No Active SIP', v:noSIP, s:'Clients to convert',c:'#94a3b8',i:'📋',p:'alerts'}, ]; var kHtml=''; kpis.forEach(function(k){ kHtml += '
'+ '
'+ '
'+k.l+'
'+k.v+'
'+k.s+'
'+ '
'+k.i+'
'; }); T('kpiGrid').innerHTML = kHtml; var rmc=['#1B4FD8','#22C55E','#F59E0B','#EC4899','#7C3AED']; var rms=STATS.rms.filter(function(r){return !CU.rm||r.name===CU.rm;}); var maxSIP=Math.max.apply(null,rms.map(function(r){return r.sip_amt;}).concat([1])); var rmHtml=''; rms.forEach(function(r,i){ rmHtml += '
'+ '
'+r.name+''+r.clients+'c · '+fmt(r.sip_amt)+'/mo
'+ '
'; }); T('rmBars').innerHTML = rmHtml; var cities=STATS.cities.slice(0,6); var maxC=Math.max.apply(null,cities.map(function(c){return c.clients;}).concat([1])); var cHtml=''; cities.forEach(function(c,i){ cHtml += '
'+ '
'+c.city+''+c.clients+'c · '+fmt(c.sip_amt)+'/mo
'+ '
'; }); T('cityBars').innerHTML = cHtml; var recents = cl.slice(-10).reverse(); var tHtml = 'NameCityRMFoliosSIP/moIns'; recents.forEach(function(c){ var cS=actS.filter(function(s){return s.clientId===c.id;}); var amt=cS.reduce(function(a,x){return a+x.sipAmount;},0); var cF=fols.filter(function(f){return f.clientId===c.id;}).length; var hasI=ins.some(function(i){return i.clientId===c.id;}); tHtml += ''+ ''+(c.name||'—')+''+ ''+(c.city||'—')+''+ ''+bd((c.rm||'—').split(' ')[0],'bl')+''+ ''+cF+''+ ''+(amt>0?fmt(amt):'—')+''+ ''+( hasI?bd('✓','gr'):bd('—','am') )+''; }); T('dashTbl').innerHTML = tHtml + ''; var alerts=[ {l:'SIP Expiring 7 days',v:exp7, c:'#EF4444',tab:'sip'}, {l:'SIP Expiring 30 days',v:exp30,c:'#F59E0B',tab:'sip'}, {l:'Insurance Renewal (30d)',v:insR30,c:'#EC4899',tab:'insurance'}, {l:'Birthdays Today',v:bdT, c:'#F59E0B',tab:'birthday'}, {l:'No Active SIP',v:noSIP, c:'#7C3AED',tab:'clients'}, ]; var aHtml=''; alerts.forEach(function(a){ aHtml += '
'+ ''+a.l+''+ ''+a.v+'
'; }); T('qAlerts').innerHTML = aHtml; } // ════════════════════════════════════════════════ // CLIENT TABLE // ════════════════════════════════════════════════ function renderCT() { var cl = visCL(); T('clSub').textContent = cl.length + ' total clients'; var s = (T('cSrch') ? T('cSrch').value : '').toLowerCase(); var actS = SIPS.filter(function(x){return x.status==='Active';}); var fil = cl.filter(function(c){ if (!s) return true; return (c.name||'').toLowerCase().indexOf(s)>=0 || (c.pan||'').toLowerCase().indexOf(s)>=0 || (c.mobile||'').indexOf(s)>=0 || (c.email||'').toLowerCase().indexOf(s)>=0|| (c.rm||'').toLowerCase().indexOf(s)>=0 || (c.city||'').toLowerCase().indexOf(s)>=0 || (c.pincode||'').indexOf(s)>=0; }); var total=fil.length, pages=Math.max(1,Math.ceil(total/cPerPage)); if(cPage>pages)cPage=1; var slice=fil.slice((cPage-1)*cPerPage, cPage*cPerPage); var html='#NamePANMobileCityPincodeRMFolSIP/moInsAction'; slice.forEach(function(c,i){ var cS=actS.filter(function(s){return s.clientId===c.id;}),amt=cS.reduce(function(a,x){return a+x.sipAmount;},0); var cF=FOLIOS.filter(function(f){return f.clientId===c.id;}).length; var hasI=INSURANCE.some(function(ins){return ins.clientId===c.id;}); html += ''+ ''+ ((cPage-1)*cPerPage+i+1) +''+ ''+(c.name||'—')+''+ ''+(c.pan||'—')+''+ ''+(c.mobile||'—')+''+ ''+(c.city||'—')+''+ ''+(c.pincode||'—')+''+ ''+bd((c.rm||'—').split(' ')[0],'bl')+''+ ''+cF+''+ ''+(amt>0?fmt(amt):'—')+''+ ''+(hasI?bd('✓','pi'):'—')+''+ ''+ ''+ ''+ ''+ ''+ ''; }); T('cTbl').innerHTML = html + ''; T('cPagi').innerHTML = 'Showing '+(total===0?0:(cPage-1)*cPerPage+1)+'–'+Math.min(cPage*cPerPage,total)+' of '+total+''+ ''+ ''+ 'Page '+cPage+'/'+pages+''+ ''+ ''; } // ════════════════════════════════════════════════ // 360 VIEW // ════════════════════════════════════════════════ function view360(id, from) { selCId = id; if(from) backPage = from; T('back360').onclick = function(){ goPage(backPage); }; var c = null; for(var i=0;i
'+ '
'+(c.name||'—')+'
'+ '
'; [['PAN',c.pan],['Mobile',c.mobile],['Email',c.email],['DOB',c.dob],['City',c.city],['Pincode',c.pincode],['RM',c.rm]].forEach(function(kv){ html+='
'+kv[0]+''+(kv[1]||'—')+'
'; }); html+='
'+ '
'+ ''+ ''+ ''+ ''+ '
'; html += '
'; // Product wise investment html += renderProductWiseInvestment(id,cF,cS,cI); // Folios html += '
📂 MF Folios ('+cF.length+')
'; if(cF.length){ html += '
AMCs: '+amcs.join(' · ')+'
'+ '
'; cF.forEach(function(f){ html+=''; }); html += '
AMCFolio No
'+f.amc+''+f.folio+'
'; } else { html += '
No folios found
'; } html += '
'; // SIPs html += '
🔄 SIP Portfolio ('+cS.length+')
'+ '
'+bd(actS.length+' Active','gr')+' '+bd(expS.length+' Expired','rd')+'
'; if(actS.length){ actS.forEach(function(s){ html += '
'+ '
'+(s.scheme||'—')+'
'+ '
Folio: '+(s.folio||'—')+'
'+ '
'+ '\u20b9'+((s.sipAmount||0).toLocaleString('en-IN'))+'/mo'+ ''+(s.startDate||'')+' → '+(s.endDate||'')+'
'+ (s.endDate&&daysDiff(s.endDate)>=0&&daysDiff(s.endDate)<=30?'
⚠️ Expiring in '+daysDiff(s.endDate)+' days
':'')+ '
'; }); } else { html += '
No active SIPs
'; } html += '
'; // Insurance html += '
🏥 Health Insurance ('+cI.length+')
'; if(cI.length){ cI.forEach(function(ins){ html += '
'+ '
'+(ins.policy||'—')+'
'+ '
Policy No: '+(ins.policyNo||'—')+'
'+ '
'+ ''+fmt(ins.premium)+''+ 'Renewal: '+(ins.renewalDate||'—')+'
'+ (ins.renewalDate&&daysDiff(ins.renewalDate)>=0&&daysDiff(ins.renewalDate)<=30?'
⚠️ Renewal in '+daysDiff(ins.renewalDate)+' days
':'')+ '
'; }); } else { html += '
No insurance records
'; } html += '
'; // Client Documents html += renderClientDocuments(id); // Summary html += '
📊 Summary
'; [['Monthly SIP','\u20b9'+monthSIP.toLocaleString('en-IN')+'/mo','#1B4FD8'], ['Active SIPs',actS.length,'#22C55E'],['Total Folios',cF.length,'#7C3AED'], ['Insurance',cI.length,'#EC4899'],['Unique AMCs',amcs.length,'#06B6D4']].forEach(function(row){ html += '
'+ ''+row[0]+''+ ''+row[1]+'
'; }); html += '
'; T('c360').innerHTML = html; goPage('360'); } function editCur(){ editId=selCId; showAdd(true); } function showAdd(edit){ var c = edit ? CLIENTS.filter(function(x){return x.id===editId;})[0] : null; T('addTitle').textContent = edit ? 'Edit Client' : 'Add New Client'; T('addBack').onclick = function(){ goPage(edit?'360':'clients'); }; T('addCancel').onclick = function(){ goPage(edit?'360':'clients'); }; var rms=[...new Set(CLIENTS.map(function(x){return x.rm;}).filter(Boolean))]; var fields=[['name','Full Name','text',c&&c.name||''],['pan','PAN','text',c&&c.pan||''], ['mobile','Mobile','text',c&&c.mobile||''],['email','Email','email',c&&c.email||''], ['dob','Date of Birth','date',c&&c.dob||''],['city','City','text',c&&c.city||''], ['pincode','Pincode','text',c&&c.pincode||''],['address','Address','text',c&&c.address||'']]; var html=''; fields.forEach(function(f){ html+='
'; }); var rmOpts=''; rms.forEach(function(r){ rmOpts+=''+r+''; }); html += '
'; T('addForm').innerHTML = html; goPage('add'); } function saveCl(){ function g(k){ var el=T('af_'+k); return el?el.value:''; } var data={name:g('name'),pan:g('pan').toUpperCase(),mobile:g('mobile'),email:g('email'), dob:g('dob'),city:g('city'),pincode:g('pincode'),address:g('address'),rm:g('rm')}; if(editId){ for(var i=0;i=0;i--){ if(CLIENTS[i].id===id) CLIENTS.splice(i,1); } renderCT(); } // Birthday direct Outlook function bdSend(id, lang){ var c=CLIENTS.filter(function(x){return x.id===id;})[0]; if(!c)return; var key=lang==='en'?'Birthday English':'Birthday Marathi'; var body=fillBody(key,c); var sub=ETMPLS[key].sub; outlookOpen(c.email||'',sub,body); sentEmails.push({n:c.name||'—',e:c.email||'—',t:key,tm:new Date().toLocaleTimeString('en-IN')}); alert('✅ Outlook opened!\nTo: '+(c.email||'(no email)')+'\nTemplate: '+key+'\nClient: '+c.name); } // ════════════════════════════════════════════════ // ALERTS // ════════════════════════════════════════════════ function renderAl(tab){ alTab=tab; var cl=visCL(), sips=visSIP(), ins=visINS(); var actS=sips.filter(function(s){return s.status==='Active';}); var sip7 = actS.filter(function(s){return s.endDate&&daysDiff(s.endDate)>=0&&daysDiff(s.endDate)<=7;}); var sip30 = actS.filter(function(s){return s.endDate&&daysDiff(s.endDate)>=0&&daysDiff(s.endDate)<=30;}); var sip60 = actS.filter(function(s){return s.endDate&&daysDiff(s.endDate)>=0&&daysDiff(s.endDate)<=60;}); var sipXp = sips.filter(function(s){return s.endDate&&daysDiff(s.endDate)<0;}); var ins30 = ins.filter(function(i){return i.renewalDate&&daysDiff(i.renewalDate)>=0&&daysDiff(i.renewalDate)<=30;}); var ins60 = ins.filter(function(i){return i.renewalDate&&daysDiff(i.renewalDate)>=0&&daysDiff(i.renewalDate)<=60;}); var insXp = ins.filter(function(i){return i.renewalDate&&daysDiff(i.renewalDate)<0;}); var bdT=cl.filter(function(c){try{var d=new Date(c.dob);return d.getMonth()===today.getMonth()&&d.getDate()===today.getDate();}catch(e){return false;}}); var bdTom=cl.filter(function(c){try{var d=new Date(c.dob),t2=new Date(today);t2.setDate(t2.getDate()+1);return d.getMonth()===t2.getMonth()&&d.getDate()===t2.getDate();}catch(e){return false;}}); var bdWk=cl.filter(function(c){try{var d=new Date(c.dob);d.setFullYear(today.getFullYear());return(d-today)/86400000>=0&&(d-today)/86400000<=7;}catch(e){return false;}}); var bdMon=cl.filter(function(c){try{return new Date(c.dob).getMonth()===today.getMonth();}catch(e){return false;}}); var noSIP=cl.filter(function(c){return !actS.some(function(s){return s.clientId===c.id;});}); var folNoSIP=cl.filter(function(c){return FOLIOS.some(function(f){return f.clientId===c.id;})&&!actS.some(function(s){return s.clientId===c.id;});}); var tabs=[ {k:'sip', l:'SIP Alerts', cnt:sip7.length+sipXp.length}, {k:'insurance', l:'Insurance 🏥', cnt:ins30.length+insXp.length}, {k:'birthday', l:'Birthdays 🎂', cnt:bdT.length+bdTom.length}, {k:'clients', l:'Client Alerts', cnt:noSIP.length}, ]; var tabHtml=''; tabs.forEach(function(t){ tabHtml+=''; }); T('alTabs').innerHTML=tabHtml; function mkS(title,cnt,rows){ var html='
'+title+''+cnt+'
'; if(rows.length){ html+='
'+rows+'
'; } else { html+='
No alerts in this category
'; } return html+'
'; } function sipRow(s){ var c=CLIENTS.filter(function(x){return x.id===s.clientId;})[0]||{}; var d=daysDiff(s.endDate); return ''+ ''+( c.name||'—')+''+ ''+(s.scheme||'—')+''+ ''+(c.mobile||'—')+''+ ''+bd((c.rm||'—').split(' ')[0],'bl')+''+ '\u20b9'+((s.sipAmount||0).toLocaleString('en-IN'))+'/mo'+ ''+(s.endDate||'—')+''+ '⚠️ '+Math.abs(d)+'d '+(d<0?'ago':'left')+''+ ''+ ''; } function insRow(i){ var c=CLIENTS.filter(function(x){return x.id===i.clientId;})[0]||{}; var d=daysDiff(i.renewalDate); return ''+ ''+( c.name||'—')+''+ ''+(i.policy||'—')+''+ ''+(c.mobile||'—')+''+ ''+bd((c.rm||'—').split(' ')[0],'bl')+''+ ''+fmt(i.premium)+''+ ''+(i.renewalDate||'—')+''+ ''+(d<0?'⚫ Expired':'⚠️ '+d+'d left')+''+ ''+ ''; } function bdRow(c){ return ''+ ''+c.name+''+ ''+(c.mobile||'—')+''+ ''+(c.email||'—')+''+ ''+c.dob+''+ ''+bd((c.rm||'—').split(' ')[0],'bl')+''+ ''+ ''+ ''+ ''; } function clRow(c){ return ''+ ''+c.name+''+ ''+(c.pan||'—')+''+ ''+(c.mobile||'—')+''+ ''+(c.city||'—')+''+ ''+bd((c.rm||'—').split(' ')[0],'bl')+''+ ''+ ''; } var colsSIP='ClientSchemeMobileRMSIP AmtEnd DateStatusOutlook'; var colsIns='ClientPolicyMobileRMPremiumRenewalStatusOutlook'; var colsBD ='ClientMobileEmailDOBRMSend'; var colsCL ='ClientPANMobileCityRMAction'; function tbl(cols, rows){ return ''+cols+''+rows+'
'; } if(tab==='sip'){ T('alContent').innerHTML= mkS('🔴 Expiring in 7 Days', sip7.length, sip7.length ?tbl(colsSIP,sip7.map(sipRow).join('')): '')+ mkS('🟡 Expiring in 30 Days', sip30.length, sip30.length ?tbl(colsSIP,sip30.map(sipRow).join('')):'')+ mkS('🟠 Expiring in 60 Days', sip60.length, sip60.length ?tbl(colsSIP,sip60.map(sipRow).join('')):'')+ mkS('⚫ Expired SIPs', sipXp.length, sipXp.length ?tbl(colsSIP,sipXp.slice(0,50).map(sipRow).join('')): ''); } else if(tab==='insurance'){ T('alContent').innerHTML= mkS('🔴 Renewal Due in 30 Days', ins30.length, ins30.length ?tbl(colsIns,ins30.map(insRow).join('')): '')+ mkS('🟡 Renewal Due in 60 Days', ins60.length, ins60.length ?tbl(colsIns,ins60.map(insRow).join('')): '')+ mkS('⚫ Expired Insurance', insXp.length, insXp.length ?tbl(colsIns,insXp.slice(0,50).map(insRow).join('')): ''); } else if(tab==='birthday'){ T('alContent').innerHTML= mkS('🎂 Today', bdT.length, bdT.length ?tbl(colsBD,bdT.map(bdRow).join('')) :'')+ mkS('🎈 Tomorrow', bdTom.length,bdTom.length?tbl(colsBD,bdTom.map(bdRow).join('')):'')+ mkS('📅 This Week', bdWk.length, bdWk.length ?tbl(colsBD,bdWk.map(bdRow).join('')) :'')+ mkS('🗓️ This Month', bdMon.length,bdMon.length?tbl(colsBD,bdMon.map(bdRow).join('')): ''); } else { T('alContent').innerHTML= mkS('⚠️ No Active SIP ('+noSIP.length+')',noSIP.length,noSIP.length?tbl(colsCL,noSIP.slice(0,100).map(clRow).join('')): '')+ mkS('📂 Folio but No SIP',folNoSIP.length,folNoSIP.length?tbl(colsCL,folNoSIP.slice(0,50).map(clRow).join('')): ''); } } function sipEmail(cid,scheme,amt,endDate){ var c=CLIENTS.filter(function(x){return x.id===cid;})[0]; if(!c)return; var body=ETMPLS['SIP Expiring'].body .replace(/\{\{NAME\}\}/g,c.name||'').replace(/\{\{RM\}\}/g,c.rm||'') .replace(/\{\{AMT\}\}/g,(amt||0).toLocaleString('en-IN')) .replace(/\{\{SCHEME\}\}/g,scheme).replace(/\{\{DATE\}\}/g,endDate); outlookOpen(c.email||'',ETMPLS['SIP Expiring'].sub,body); sentEmails.push({n:c.name||'—',e:c.email||'—',t:'SIP Expiring',tm:new Date().toLocaleTimeString('en-IN')}); alert('✅ Outlook opened!\nClient: '+c.name+'\nTemplate: SIP Expiry Alert'); } function insEmail(cid){ var c=CLIENTS.filter(function(x){return x.id===cid;})[0]; if(!c)return; var body=fillBody('Insurance Renewal',c); outlookOpen(c.email||'',ETMPLS['Insurance Renewal'].sub,body); sentEmails.push({n:c.name||'—',e:c.email||'—',t:'Insurance Renewal',tm:new Date().toLocaleTimeString('en-IN')}); alert('✅ Outlook opened!\nClient: '+c.name+'\nTemplate: Insurance Renewal'); } // ════════════════════════════════════════════════ // REPORTS — ALL 7 TABS // ════════════════════════════════════════════════ function renderRp(tab){ rpTab=tab; var cl=visCL(), sips=visSIP(), ins=visINS(), actS=sips.filter(function(s){return s.status==='Active';}); var fols=FOLIOS.filter(function(f){return cl.some(function(c){return c.id===f.clientId;});}); var tabs=[['rm','RM Wise'],['city','City Wise'],['pincode','Pincode Wise'], ['product','Product Wise'],['amc','AMC Wise'],['scheme','Top Schemes'],['insurance','Insurance']]; var tHtml=''; tabs.forEach(function(t){ tHtml+=''; }); T('rpTabs').innerHTML=tHtml; var html=''; if(tab==='rm'){ var rms=[...new Set(CLIENTS.map(function(c){return c.rm;}).filter(Boolean))]; var data=rms.map(function(rm){ var rCl=cl.filter(function(c){return c.rm===rm;}); var rS=actS.filter(function(s){return rCl.some(function(c){return c.id===s.clientId;});}); var rI=ins.filter(function(i){return i.rm===rm;}); return {rm:rm,cnt:rCl.length,sips:rS.length,amt:rS.reduce(function(a,x){return a+x.sipAmount;},0), fols:fols.filter(function(f){return rCl.some(function(c){return c.id===f.clientId;});}).length,ins:rI.length}; }).sort(function(a,b){return b.cnt-a.cnt;}); html=''; data.forEach(function(r){ html+=''+ ''+ ''+ ''; }); html+='
RM NameClientsFoliosActive SIPsMonthly SIPInsuranceAction
'+r.rm+''+bd(r.cnt,'bl')+''+r.fols+''+bd(r.sips,'gr')+''+fmt(r.amt)+'/mo'+bd(r.ins,'pi')+'
'; } else if(tab==='city'){ var cities=[...new Set(cl.map(function(c){return c.city;}).filter(function(x){return x&&x!=='Nan';}))]; var data=cities.map(function(city){ var cCl=cl.filter(function(c){return c.city===city;}); var cS=actS.filter(function(s){return cCl.some(function(c){return c.id===s.clientId;});}); return{city:city,cnt:cCl.length,sips:cS.length,amt:cS.reduce(function(a,x){return a+x.sipAmount;},0)}; }).sort(function(a,b){return b.cnt-a.cnt;}); html=''; data.forEach(function(r){ html+=''+ ''+ ''+ ''; }); html+='
CityClientsActive SIPsMonthly SIPAction
'+r.city+''+bd(r.cnt,'bl')+''+r.sips+''+fmt(r.amt)+'/mo
'; } else if(tab==='pincode'){ var pcs=STATS.pincodes||[]; html=''; pcs.forEach(function(r){ html+=''+ ''+ ''; }); html+='
PincodeCityClientsAction
'+r.pincode+''+(r.city||'—')+''+bd(r.clients,'bl')+'
'; } else if(tab==='product'){ var ids=new Set(cl.map(function(c){return c.id;})); var prods=[ {p:'Mutual Fund (Folios)',ico:'📂',cnt:fols.length,clients:[...new Set(fols.map(function(f){return f.clientId;}))].length,amt:0,clr:'#7C3AED'}, {p:'Active SIP',ico:'🔄',cnt:actS.filter(function(s){return ids.has(s.clientId);}).length, clients:[...new Set(actS.filter(function(s){return ids.has(s.clientId);}).map(function(s){return s.clientId;}))].length, amt:actS.filter(function(s){return ids.has(s.clientId);}).reduce(function(a,x){return a+x.sipAmount;},0),clr:'#22C55E'}, {p:'Expired SIP',ico:'⏱️',cnt:sips.filter(function(s){return s.status==='Expired'&&ids.has(s.clientId);}).length, clients:[...new Set(sips.filter(function(s){return s.status==='Expired'&&ids.has(s.clientId);}).map(function(s){return s.clientId;}))].length,amt:0,clr:'#94a3b8'}, {p:'Health Insurance',ico:'🏥',cnt:ins.filter(function(i){return ids.has(i.clientId);}).length, clients:[...new Set(ins.filter(function(i){return ids.has(i.clientId);}).map(function(i){return i.clientId;}))].length, amt:ins.filter(function(i){return ids.has(i.clientId);}).reduce(function(a,x){return a+x.premium;},0),clr:'#EC4899'}, ]; html=''; prods.forEach(function(r){ html+=''+ ''+ ''; }); html+='
ProductRecordsUnique ClientsBook Value / Monthly
'+r.ico+' '+r.p+''+bd(r.cnt,'bl')+''+r.clients+''+(r.amt>0?fmt(r.amt)+(r.p.indexOf('SIP')>=0?'/mo':''):'—')+'
'; } else if(tab==='amc'){ var amcMap={}; fols.forEach(function(f){amcMap[f.amc]=(amcMap[f.amc]||0)+1;}); var data=Object.entries(amcMap).sort(function(a,b){return b[1]-a[1];}); html=''; data.forEach(function(kv){ html+=''+ ''+ ''; }); html+='
AMC NameFoliosShare %Action
'+kv[0]+''+kv[1]+''+((kv[1]/fols.length)*100).toFixed(1)+'%
'; } else if(tab==='scheme'){ var schMap={}; actS.filter(function(s){return ids.has(s.clientId);}).forEach(function(s){ if(!schMap[s.scheme])schMap[s.scheme]={cnt:0,amt:0}; schMap[s.scheme].cnt++; schMap[s.scheme].amt+=s.sipAmount; }); var data=Object.entries(schMap).sort(function(a,b){return b[1].amt-a[1].amt;}).slice(0,30); html=''; data.forEach(function(kv){ html+=''+ ''+ ''; }); html+='
Scheme NameInvestorsMonthly SIPAction
'+kv[0]+''+kv[1].cnt+''+fmt(kv[1].amt)+'/mo
'; } else if(tab==='insurance'){ var byP={}; ins.forEach(function(i){if(!byP[i.policy])byP[i.policy]={cnt:0,prem:0};byP[i.policy].cnt++;byP[i.policy].prem+=i.premium;}); var data=Object.entries(byP).sort(function(a,b){return b[1].cnt-a[1].cnt;}); html='
'+ 'Total: '+ins.length+''+ 'Clients: '+ [...new Set(ins.map(function(i){return i.clientId;}))].length +''+ 'Total Premium: '+fmt(ins.reduce(function(a,x){return a+x.premium;},0))+''+ 'Renewal Due 30d: '+ins.filter(function(i){return i.renewalDate&&daysDiff(i.renewalDate)>=0&&daysDiff(i.renewalDate)<=30;}).length+''+ '
'+ ''; data.forEach(function(kv){ html+=''+ ''+ ''; }); html+='
Policy NameCountTotal Premium
'+kv[0]+''+bd(kv[1].cnt,'pi')+''+fmt(kv[1].prem)+'
'; } T('rpContent').innerHTML = html; } // ════════════════════════════════════════════════ // PRODUCT WISE INVESTMENT TAB + DOCUMENT VIEW // ════════════════════════════════════════════════ function getClientProductRows(){ var rows=[]; visCL().forEach(function(c){ var fol=FOLIOS.filter(function(f){return f.clientId===c.id;}); var sip=SIPS.filter(function(x){return x.clientId===c.id;}); var act=sip.filter(function(x){return x.status==='Active';}); var ins=INSURANCE.filter(function(x){return x.clientId===c.id;}); if(fol.length||act.length){ rows.push({client:c,product:'Mutual Fund',details:(fol.length+' Folios / '+act.length+' Active SIP'),scheme:act.map(function(x){return x.scheme;}).filter(Boolean).join(' | ') || fol.map(function(x){return x.amc;}).filter(Boolean).join(' | '),amount:act.reduce(function(a,x){return a+(Number(x.sipAmount)||0);},0),valueType:'Monthly SIP'}); } ins.forEach(function(i){ var low=String(i.type||i.policy||'').toLowerCase(); rows.push({client:c,product:low.indexOf('term')>=0?'Term Insurance':'Health Insurance',details:i.policyNo||'Policy',scheme:i.policy||'Insurance',amount:Number(i.premium)||0,valueType:'Premium'}); }); }); return rows; } // Old Product Wise renderer replaced by enhanced product-wise module above. function renderDocumentsTab(){ var q=(T('docSrch')?T('docSrch').value:'').toLowerCase().trim(); var rows=getAllDocumentRows().filter(function(r){var c=r.client,d=r.doc;return !q || [c.name,c.pan,c.rm,d.type,d.name,d.file,d.date].join(' ').toLowerCase().indexOf(q)>=0;}); var clients=[...new Set(rows.map(function(r){return r.id;}))].length; var pan=rows.filter(function(r){return String(r.doc.type).toLowerCase()==='pan';}).length; var aad=rows.filter(function(r){return String(r.doc.type).toLowerCase().indexOf('aad')>=0;}).length; T('docKpi').innerHTML = '
Total Docs
'+rows.length+'
Uploaded entries
'+ '
Clients
'+clients+'
With documents
'+ '
PAN Docs
'+pan+'
PAN uploaded
'+ '
Aadhaar Docs
'+aad+'
Aadhaar uploaded
'; var html='ClientPANRMTypeDocument NameFile NameUploaded OnViewAction'; if(rows.length){ rows.forEach(function(r){var c=r.client,d=r.doc; html+=''+escHtml(c.name||'—')+''+escHtml(c.pan||'—')+''+escHtml(c.rm||'—')+''+docIcon(d.type)+' '+escHtml(d.type)+''+escHtml(d.name)+''+escHtml(d.file)+'
'+Math.round((d.size||0)/1024)+' KB
'+escHtml(d.date)+'';}); } else html+='No uploaded documents found. Client 360 View me document upload kare.'; html+=''; T('docTbl').innerHTML=html; } // ════════════════════════════════════════════════ // ANALYTICS // ════════════════════════════════════════════════ function renderAna(){ var cl=visCL(), actS=SIPS.filter(function(s){return s.status==='Active';}); var rmc=['#1B4FD8','#22C55E','#F59E0B','#EC4899','#7C3AED','#06B6D4']; var rms=[...new Set(cl.map(function(c){return c.rm;}).filter(Boolean))]; var cities=[...new Set(cl.map(function(c){return c.city;}).filter(function(x){return x&&x!=='Nan';}))].slice(0,8); var pcs=(STATS.pincodes||[]).slice(0,8); function mkBar(label,sub,pct,color,onclick,sel){ return '
'+ '
'+label+''+sub+'
'+ '
'; } var rmHtml='',cityHtml='',pcHtml=''; rms.forEach(function(rm,i){ var cnt=cl.filter(function(c){return c.rm===rm;}).length; var sel=anaFil&&anaFil.key==='rm'&&anaFil.val===rm; rmHtml+=mkBar(rm,cnt+' clients',Math.round(cnt/cl.length*100),rmc[i%6], "anaFil={key:'rm',val:'"+rm+"'};renderAna()",sel); }); cities.forEach(function(city,i){ var cnt=cl.filter(function(c){return c.city===city;}).length; var sel=anaFil&&anaFil.key==='city'&&anaFil.val===city; cityHtml+=mkBar(city,cnt+' clients',Math.round(cnt/cl.length*100),rmc[i%6], "anaFil={key:'city',val:'"+city+"'};renderAna()",sel); }); pcs.forEach(function(p,i){ var sel=anaFil&&anaFil.key==='pincode'&&anaFil.val===p.pincode; pcHtml+=mkBar(p.pincode,(p.city||'')+'·'+p.clients+'c',Math.round(p.clients/cl.length*100),rmc[i%6], "anaFil={key:'pincode',val:'"+p.pincode+"'};renderAna()",sel); }); var filtered=cl; if(anaFil){ if(anaFil.key==='pincode') filtered=cl.filter(function(c){return (c.pincode||'').split('.')[0]===anaFil.val;}); else if(anaFil.key==='amc') filtered=[...new Set(FOLIOS.filter(function(f){return f.amc===anaFil.val;}).map(function(f){return f.clientId;}))].map(function(id){return CLIENTS.filter(function(c){return c.id===id;})[0];}).filter(Boolean); else if(anaFil.key==='scheme') filtered=[...new Set(SIPS.filter(function(s){return s.scheme===anaFil.val;}).map(function(s){return s.clientId;}))].map(function(id){return CLIENTS.filter(function(c){return c.id===id;})[0];}).filter(Boolean); else filtered=cl.filter(function(c){return c[anaFil.key]===anaFil.val;}); } T('anaSub').textContent = anaFil ? 'Showing '+filtered.length+' clients for: '+anaFil.val : 'Click bars to filter · Click rows for 360°'; T('anaClr').style.display = anaFil ? 'block' : 'none'; var banner = anaFil ? '
'+ '🔍 '+anaFil.val+' — '+filtered.length+' clients'+ '
' : ''; var tblHtml=''; filtered.slice(0,100).forEach(function(c){ var sp=actS.filter(function(s){return s.clientId===c.id;}).reduce(function(a,x){return a+x.sipAmount;},0); var fl=FOLIOS.filter(function(f){return f.clientId===c.id;}).length; var hasI=INSURANCE.some(function(i){return i.clientId===c.id;}); tblHtml+=''+ ''+ ''+ ''+ ''+ ''+ ''+ ''+ ''; }); tblHtml += '
NamePANMobileCityPincodeRMFoliosSIP/moIns
'+(c.name||'—')+''+(c.pan||'—')+''+(c.mobile||'—')+''+(c.city||'—')+''+(c.pincode||'—')+''+bd((c.rm||'—').split(' ')[0],'bl')+''+fl+''+(sp>0?fmt(sp):'—')+''+(hasI?bd('✓','pi'):'—')+'
'; if(filtered.length>100) tblHtml += '
Showing 100 of '+filtered.length+'
'; T('anaContent').innerHTML = banner + '
'+ '
Filter by RM
'+rmHtml+'
'+ '
Filter by City
'+cityHtml+'
'+ '
Filter by Pincode
'+pcHtml+'
'+ '
'+ '
'+ '
'+(anaFil?anaFil.val:'All Clients')+' ('+filtered.length+')
'+ '
'+tblHtml+'
'; } // ════════════════════════════════════════════════ // EMAIL TEMPLATES — FULL OUTLOOK INTEGRATION // ════════════════════════════════════════════════ function renderEmail(){ var cl=visCL(); var tHtml='
Templates ('+Object.keys(ETMPLS).length+')
'; Object.keys(ETMPLS).forEach(function(k){ tHtml+=''+ETMPLS[k].ico+' '+k+''; }); T('tmplList').innerHTML=tHtml; renderEP(cl); } function renderEP(cl){ var tmpl=ETMPLS[selTmpl]; var rCl = selRecip==='all' ? null : cl.filter(function(c){return c.id===selRecip;})[0]; var pc = rCl || cl[0] || {name:'Valued Client',rm:'Your RM',email:''}; var body = fillBody(selTmpl, pc); var opts=''; cl.slice(0,300).forEach(function(c){ opts+=''; }); T('tmplPrev').innerHTML= '
'+ '
'+tmpl.ico+' '+selTmpl+'
'+ '
Subject: '+tmpl.sub+'
'+ '
'+ ''+ ''+ '
'+ buildEP(tmpl.sub, body, tmpl.ico); if(sentEmails.length){ T('sentLog').style.display='block'; var sHtml='
📋 Sent Log ('+sentEmails.length+')
'; sentEmails.slice(-10).reverse().forEach(function(s){ sHtml+='
'+ ''+s.n+' · '+s.e+''+ '✅ '+s.t+' · '+s.tm+'
'; }); T('sentLog').innerHTML=sHtml; } } function doSend(){ var cl=visCL(), tmpl=ETMPLS[selTmpl]; if(selRecip!=='all'){ var c=cl.filter(function(x){return x.id===selRecip;})[0]; if(!c)return; outlookOpen(c.email||'', tmpl.sub, fillBody(selTmpl,c)); sentEmails.push({n:c.name||'—',e:c.email||'—',t:selTmpl,tm:new Date().toLocaleTimeString('en-IN')}); alert('✅ Outlook opened!\nTo: '+(c.email||'(no email)')+'\nTemplate: '+selTmpl); } else { var first=cl[0]; if(first){ outlookOpen(first.email||'', tmpl.sub, fillBody(selTmpl,first)); } cl.forEach(function(c){ sentEmails.push({n:c.name||'—',e:c.email||'—',t:selTmpl,tm:new Date().toLocaleTimeString('en-IN')}); }); alert('✅ Outlook opened for first client.\nAll '+cl.length+' clients logged.\nTemplate: '+selTmpl); } renderEmail(); } // ════════════════════════════════════════════════ // NEW FUND LAUNCH // ════════════════════════════════════════════════ function nfLive(){ var name=(T('nfName')&&T('nfName').value)||'New Fund'; var amc =(T('nfAMC') &&T('nfAMC').value) ||'AMC'; var cat =(T('nfCat') &&T('nfCat').value) ||'Equity'; var risk=(T('nfRisk')&&T('nfRisk').value)||'Moderate'; var sip =(T('nfSIP') &&T('nfSIP').value) ||'500'; var ls =(T('nfLS') &&T('nfLS').value) ||'5000'; var hl =(T('nfHL') &&T('nfHL').value) ||''; var opn =(T('nfOpen')&&T('nfOpen').value)||''; var cls =(T('nfClose')&&T('nfClose').value)||''; var tgt =(T('nfTo') &&T('nfTo').value) ||'all'; var cl=visCL(), tCl=cl; var rmMap={rm_rutik:'Rutik Savarkar',rm_satish_m:'Satish Magan Bangar',rm_satish:'Satish Bangar',rm_sarika:'Sarika Kedari',rm_suvarna:'Suvarna Bangar'}; if(tgt==='nosip') tCl=cl.filter(function(c){return !SIPS.some(function(s){return s.clientId===c.id&&s.status==='Active';});}); else if(rmMap[tgt]) tCl=cl.filter(function(c){return c.rm===rmMap[tgt];}); var hlLines=hl.split('\n').filter(function(x){return x.trim();}); var bodyTpl='Dear NAME,\n\nWe are pleased to present an exciting new investment opportunity:\n\n\ud83d\ude80 '+name+'\n\ud83c\udfe6 AMC: '+amc+'\n\ud83d\udcc8 Category: '+cat+' | Risk: '+risk+ (hlLines.length?'\n\n\u2705 Key Highlights:\n'+hlLines.join('\n'):'')+ '\n\n\ud83d\udcb0 Min SIP: \u20b9'+Number(sip||0).toLocaleString('en-IN')+'/month'+ '\n\ud83d\udcbc Min Lump Sum: \u20b9'+Number(ls||0).toLocaleString('en-IN')+ (opn?'\n\ud83d\udcc5 NFO Opens: '+opn:'')+ (cls?'\n\ud83d\udcc5 NFO Closes: '+cls:'')+ '\n\nDon\'t miss this opportunity! Contact your RM RM to invest today.\n\nWarm regards,\nTeam ONE CALL Financial Services'; var pc=tCl[0]||{name:'Valued Client',rm:'Your RM'}; var preview=bodyTpl.replace(/NAME/g,pc.name||'').replace(/RM/g,pc.rm||''); var subj='\ud83d\ude80 New Fund: '+name+' – '+amc; var rcpHtml=''; tCl.slice(0,3).forEach(function(c){ rcpHtml+=''+( c.name&&c.name.split(' ')[0]||'—' )+''; }); T('nfPrev').innerHTML= '
Recipients: '+tCl.length+' clients '+rcpHtml+(tCl.length>3?' +'+( tCl.length-3)+' more':'')+'
'+ buildEP(subj, preview, '\ud83d\ude80'); T('nfPrev')._d = {subj:subj, bodyTpl:bodyTpl, tCl:tCl}; } function sendNF(){ if(!T('nfName').value){alert('Please enter Fund Name first.');return;} var d=T('nfPrev')&&T('nfPrev')._d; if(!d||!d.tCl.length){alert('No clients selected.');return;} var c=d.tCl[0]; outlookOpen(c.email||'', d.subj, d.bodyTpl.replace(/NAME/g,c.name||'').replace(/RM/g,c.rm||'')); d.tCl.forEach(function(x){ sentEmails.push({n:x.name||'—',e:x.email||'—',t:'New Fund Launch',tm:new Date().toLocaleTimeString('en-IN')}); }); alert('✅ Outlook opened!\nClient: '+c.name+'\nTotal logged: '+d.tCl.length+' clients'); } // ════════════════════════════════════════════════ // EXPORT // ════════════════════════════════════════════════ function renderExp(){ var cl=visCL(), actS=SIPS.filter(function(s){return s.status==='Active';}).filter(function(s){return cl.some(function(c){return c.id===s.clientId;});}); var ins=INSURANCE.filter(function(i){return cl.some(function(c){return c.id===i.clientId;});}); var exps=[ {ico:'👥',t:'Client Master CSV',d:'Name, PAN, Mobile, Email, DOB, City, RM',fn:"doCSV('clients')"}, {ico:'🔄',t:'Active SIP Report',d:'Client, Scheme, Folio, SIP Amt, Start/End',fn:"doCSV('sip')"}, {ico:'🏥',t:'Insurance Report',d:'Client, Policy, Policy No, Premium, Renewal',fn:"doCSV('ins')"}, {ico:'⚠️',t:'SIP Expiry (30 days)',d:'SIPs expiring in next 30 days',fn:"doCSV('exp30')"}, {ico:'🎂',t:'Birthday List',d:'This month birthdays with contact',fn:"doCSV('bd')"}, {ico:'🏙️',t:'Pincode Report',d:'Clients grouped by pincode',fn:"doCSV('pincode')"}, ]; var cHtml=''; exps.forEach(function(e){ cHtml+='
'+ '
'+e.ico+'
'+ '
'+e.t+'
'+ '
'+e.d+'
'+ '
'; }); T('expCards').innerHTML=cHtml; T('expMeta').innerHTML='
Export Summary
'+ '
'+ [['👥 Clients',cl.length,'#1B4FD8'], ['📂 Folios',FOLIOS.filter(function(f){return cl.some(function(c){return c.id===f.clientId;});}).length,'#7C3AED'], ['🔄 Active SIPs',actS.length,'#22C55E'], ['🏥 Insurance',ins.length,'#EC4899']].map(function(x){ return '
'+ '
'+x[0]+'
'+ '
'+x[1]+'
'; }).join('') + '
'; } function doCSV(type){ var cl=visCL(), h='', rows=[]; if(type==='clients'){ h='Name,PAN,Mobile,Email,DOB,City,Pincode,RM\n'; rows=cl.map(function(c){return '"'+(c.name||'')+'","'+(c.pan||'')+'","'+(c.mobile||'')+'","'+(c.email||'')+'","'+(c.dob||'')+'","'+(c.city||'')+'","'+(c.pincode||'')+'","'+(c.rm||'')+'"';}).join('\n'); } else if(type==='sip'){ var act=SIPS.filter(function(s){return s.status==='Active'&&cl.some(function(c){return c.id===s.clientId;});}); h='Client,PAN,Mobile,Scheme,Folio,SIP Amt,Start,End,RM\n'; rows=act.map(function(s){var c=CLIENTS.filter(function(x){return x.id===s.clientId;})[0]||{};return '"'+(c.name||'')+'","'+(c.pan||'')+'","'+(c.mobile||'')+'","'+(s.scheme||'')+'","'+(s.folio||'')+'","'+s.sipAmount+'","'+(s.startDate||'')+'","'+(s.endDate||'')+'","'+(c.rm||'')+'"';}).join('\n'); } else if(type==='ins'){ var ins=INSURANCE.filter(function(i){return cl.some(function(c){return c.id===i.clientId;});}); h='Client,Mobile,Policy,Policy No,Premium,Renewal Date,RM\n'; rows=ins.map(function(i){var c=CLIENTS.filter(function(x){return x.id===i.clientId;})[0]||{};return '"'+(c.name||'')+'","'+(c.mobile||'')+'","'+(i.policy||'')+'","'+(i.policyNo||'')+'","'+i.premium+'","'+(i.renewalDate||'')+'","'+(i.rm||'')+'"';}).join('\n'); } else if(type==='exp30'){ var act=SIPS.filter(function(s){return s.status==='Active'&&s.endDate&&daysDiff(s.endDate)>=0&&daysDiff(s.endDate)<=30&&cl.some(function(c){return c.id===s.clientId;});}); h='Client,Mobile,Scheme,SIP Amt,End Date,Days Left,RM\n'; rows=act.map(function(s){var c=CLIENTS.filter(function(x){return x.id===s.clientId;})[0]||{};return '"'+(c.name||'')+'","'+(c.mobile||'')+'","'+(s.scheme||'')+'","'+s.sipAmount+'","'+(s.endDate||'')+'","'+daysDiff(s.endDate)+'","'+(c.rm||'')+'"';}).join('\n'); } else if(type==='bd'){ var bdM=cl.filter(function(c){try{return new Date(c.dob).getMonth()===today.getMonth();}catch(e){return false;}}); h='Name,PAN,Mobile,Email,DOB,City,RM\n'; rows=bdM.map(function(c){return '"'+(c.name||'')+'","'+(c.pan||'')+'","'+(c.mobile||'')+'","'+(c.email||'')+'","'+(c.dob||'')+'","'+(c.city||'')+'","'+(c.rm||'')+'"';}).join('\n'); } else if(type==='pincode'){ h='Pincode,City,Clients\n'; rows=(STATS.pincodes||[]).map(function(p){return '"'+p.pincode+'","'+(p.city||'')+'","'+p.clients+'"';}).join('\n'); } var a=document.createElement('a'); a.href=URL.createObjectURL(new Blob([h+rows],{type:'text/csv'})); a.download='onecall_'+type+'.csv'; a.click(); } // ════════════════════════════════════════════════ // USER MANAGEMENT // ════════════════════════════════════════════════ function renderUsers(){ var html='NameUsernameRoleStatusAction'; USERS.forEach(function(u){ html+=''+u.name+''+ ''+u.u+''+ ''+bd(u.role,u.role==='Admin'?'am':u.role==='RM'?'bl':'gr')+''+ ''+bd('Active','gr')+''+ ''; }); T('uTbl').innerHTML = html + ''; } // ════════════════════════════════════════════════ // FINAL FIX PATCH: dynamic client + product sync everywhere // ════════════════════════════════════════════════ function ocGetJSON(k,def){try{return JSON.parse(localStorage.getItem(k)||JSON.stringify(def));}catch(e){return def;}} function ocSetJSON(k,v){localStorage.setItem(k,JSON.stringify(v||[]));} function getClientStore(){return ocGetJSON('ONECALL_MANUAL_CLIENTS',[]);} function setClientStore(a){ocSetJSON('ONECALL_MANUAL_CLIENTS',a);} function allClientsMaster(){ var m={}, out=[]; CLIENTS.forEach(function(c){m[String(c.id)]=Object.assign({},c,{source:c.source||'System'});}); getClientStore().forEach(function(c){if(c.deleted){delete m[String(c.id)];}else{m[String(c.id)]=Object.assign({},m[String(c.id)]||{},c,{source:'Manual'});}}); Object.keys(m).forEach(function(k){out.push(m[k]);}); out.sort(function(a,b){return (Number(a.id)||0)-(Number(b.id)||0);}); return out; } visCL=function(){var a=allClientsMaster();return CU&&CU.rm?a.filter(function(c){return c.rm===CU.rm;}):a;}; visSIP=function(){var ids=new Set(visCL().map(function(c){return Number(c.id);}));return SIPS.filter(function(s){return ids.has(Number(s.clientId));});}; visINS=function(){var ids=new Set(visCL().map(function(c){return Number(c.id);}));return INSURANCE.filter(function(i){return ids.has(Number(i.clientId));});}; clientById=function(id){return allClientsMaster().filter(function(c){return String(c.id)===String(id);})[0]||{};}; function ocProductKind(r){var p=String((r&&r.product)||'').toLowerCase(); if(p.indexOf('term')>=0)return 'term'; if(p.indexOf('health')>=0)return 'health'; if(p.indexOf('mutual')>=0||p.indexOf('sip')>=0)return 'mf'; return 'other';} function ocManualRowsAll(){return getPEStore().map(function(e){var c=clientById(e.clientId);return Object.assign({},e,{source:'Manual',client:c.name||e.client||'',pan:c.pan||e.pan||'',mobile:c.mobile||'',rm:c.rm||e.rm||''});});} manualProductRows=function(){var ids=new Set(visCL().map(function(c){return Number(c.id);}));return ocManualRowsAll().filter(function(e){return ids.has(Number(e.clientId));});}; function allVisibleProductRows(){return allProductRows();} function rowsForClient(id){return allVisibleProductRows().filter(function(r){return String(r.clientId)===String(id);});} function ocRefreshAll(){ try{renderDash();}catch(e){} try{renderCT();}catch(e){} try{renderProductEntry();}catch(e){} try{renderProductWiseTab();}catch(e){} try{renderAna();}catch(e){} try{renderReports();}catch(e){} } showAdd=function(edit){ var c=null; if(edit&&editId)c=clientById(editId); T('addTitle').textContent=edit?'Edit Client / Manual Update':'Add New Client'; var rms=[...new Set(allClientsMaster().map(function(x){return x.rm;}).filter(Boolean))].sort(); if(!rms.length)rms=['Priya Gaonkar','Rutik Savarkar','Satish Bangar','Sarika Kedari']; var fields=[ ['name','Client Name','text',c&&c.name||''],['pan','PAN','text',c&&c.pan||''],['mobile','Mobile','text',c&&c.mobile||''],['email','Email','email',c&&c.email||''], ['dob','DOB','date',c&&c.dob||''],['city','City','text',c&&c.city||''],['pincode','Pincode','text',c&&c.pincode||''],['address','Address','text',c&&c.address||''] ]; var html=''; fields.forEach(function(f){html+='
';}); var rmOpts=rms.map(function(r){return '';}).join(''); html+='
'+ '
'+ '
'; T('addForm').innerHTML=html; goPage('add'); }; saveCl=async function(){ function g(k){var el=T('af_'+k);return el?el.value:'';} var data={name:g('name').trim(),pan:g('pan').trim().toUpperCase(),mobile:g('mobile').trim(),email:g('email').trim().toLowerCase(),dob:g('dob'),city:g('city').trim(),pincode:g('pincode').trim(),address:g('address').trim(),rm:g('rm'),accountStatus:g('accountStatus')||'Account Open',docStatus:g('docStatus')||'Pending',updatedOn:new Date().toLocaleString('en-IN')}; if(!data.name){alert('Client Name required hai.');return;} if(data.email&&!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)){alert('Valid Email ID enter karein.');return;} var wasEdit=!!editId, savedId=editId||Date.now(); data.id=savedId; data.source='Manual'; var store=getClientStore(); if(wasEdit){ var done=false; for(var i=0;i=0&&daysDiff(s.endDate)<=7;}).length; var exp30=mfRows.filter(function(s){return s.endDate&&daysDiff(s.endDate)>=0&&daysDiff(s.endDate)<=30;}).length; var noProd=cl.filter(function(c){return !rows.some(function(r){return String(r.clientId)===String(c.id);});}).length; var kpis=[ {l:'Total Clients',v:cl.length,s:'Registered + manual',c:'#0A2463',i:'👥',p:'clients'}, {l:'Monthly SIP Book',v:fmt(totalSIP)+'/mo',s:mfRows.length+' active SIPs',c:'#1B4FD8',i:'🔄',p:'productwise'}, {l:'Product Records',v:rows.length,s:'All products',c:'#7C3AED',i:'💼',p:'productwise'}, {l:'Health Insurance',v:healthRows.length,s:fmt(healthRows.reduce(function(a,x){return a+(Number(x.amount)||0);},0)),c:'#EC4899',i:'🏥',p:'productwise'}, {l:'Term Insurance',v:termRows.length,s:fmt(termRows.reduce(function(a,x){return a+(Number(x.amount)||0);},0)),c:'#7C3AED',i:'🛡️',p:'productwise'}, {l:'SIP Expiring (7d)',v:exp7,s:exp30+' in 30d',c:'#EF4444',i:'⚠️',p:'alerts'}, {l:'Birthdays Today',v:bdT,s:'Click to send wishes',c:'#F59E0B',i:'🎂',p:'alerts'}, {l:'No Product',v:noProd,s:'Clients to convert',c:'#94a3b8',i:'📋',p:'alerts'} ]; T('kpiGrid').innerHTML=kpis.map(function(k){return '
'+k.l+'
'+k.v+'
'+k.s+'
'+k.i+'
';}).join(''); var rmMap={}; cl.forEach(function(c){var r=c.rm||'Unassigned'; if(!rmMap[r])rmMap[r]={clients:0,sip:0}; rmMap[r].clients++;}); mfRows.forEach(function(r){var rm=r.rm||'Unassigned'; if(!rmMap[rm])rmMap[rm]={clients:0,sip:0}; rmMap[rm].sip+=Number(r.amount)||0;}); var rms=Object.keys(rmMap).map(function(r){return {name:r,clients:rmMap[r].clients,sip:rmMap[r].sip};}).sort(function(a,b){return b.sip-a.sip;}).slice(0,6); var maxS=Math.max.apply(null,rms.map(function(r){return r.sip;}).concat([1])); T('rmBars').innerHTML=rms.map(function(r,i){return '
'+escHtml(r.name)+''+r.clients+'c · '+fmt(r.sip)+'/mo
';}).join(''); var cityMap={}; cl.forEach(function(c){var city=c.city||'—'; cityMap[city]=(cityMap[city]||0)+1;}); var cities=Object.keys(cityMap).map(function(c){return {city:c,clients:cityMap[c]};}).sort(function(a,b){return b.clients-a.clients;}).slice(0,6); var maxC=Math.max.apply(null,cities.map(function(c){return c.clients;}).concat([1])); T('cityBars').innerHTML=cities.map(function(c){return '
'+escHtml(c.city)+''+c.clients+' clients
';}).join(''); var recents=cl.slice(-10).reverse(); var t='NameCityRMAccountMF SIPHealthTerm'; recents.forEach(function(c){var cr=rowsForClient(c.id), mf=cr.filter(function(r){return ocProductKind(r)==='mf';}).reduce(function(a,x){return a+(Number(x.amount)||0);},0), h=cr.filter(function(r){return ocProductKind(r)==='health';}).length, tr=cr.filter(function(r){return ocProductKind(r)==='term';}).length; t+=''+escHtml(c.name||'—')+''+escHtml(c.city||'—')+''+bd(escHtml((c.rm||'—').split(' ')[0]),'bl')+''+bd(escHtml(c.accountStatus||'Account Open'),(c.accountStatus==='Not Open'?'rd':(c.accountStatus==='Account Opening WIP'?'am':'gr')))+''+(mf>0?fmt(mf):'—')+''+(h?bd(h,'pi'):bd('—','am'))+''+(tr?bd(tr,'vi'):bd('—','am'))+'';}); T('dashTbl').innerHTML=t+''; var alerts=[{l:'SIP Expiring 7 days',v:exp7,c:'#EF4444',tab:'sip'},{l:'Health Insurance',v:healthRows.length,c:'#EC4899',tab:'insurance'},{l:'Term Insurance',v:termRows.length,c:'#7C3AED',tab:'insurance'},{l:'Birthdays Today',v:bdT,c:'#F59E0B',tab:'birthday'},{l:'No Product',v:noProd,c:'#94a3b8',tab:'clients'}]; T('qAlerts').innerHTML=alerts.map(function(a){return '
'+a.l+''+a.v+'
';}).join(''); }; renderCT=function(){ var cl=visCL(); T('clSub').textContent=cl.length+' total clients'; var s=(T('cSrch')?T('cSrch').value:'').toLowerCase(); var fil=cl.filter(function(c){var t=[c.name,c.pan,c.mobile,c.email,c.rm,c.city,c.pincode,c.accountStatus,c.docStatus].join(' ').toLowerCase();return !s||t.indexOf(s)>=0;}); var total=fil.length,pages=Math.max(1,Math.ceil(total/cPerPage)); if(cPage>pages)cPage=1; var slice=fil.slice((cPage-1)*cPerPage,cPage*cPerPage), rows=allVisibleProductRows(); var html='#NamePANMobileCityRMAccountMF SIPHealthTermAction'; slice.forEach(function(c,i){var cr=rows.filter(function(r){return String(r.clientId)===String(c.id);}), mf=cr.filter(function(r){return ocProductKind(r)==='mf';}).reduce(function(a,x){return a+(Number(x.amount)||0);},0), h=cr.filter(function(r){return ocProductKind(r)==='health';}).length, tr=cr.filter(function(r){return ocProductKind(r)==='term';}).length; html+=''+((cPage-1)*cPerPage+i+1)+''+escHtml(c.name||'—')+'
'+escHtml(c.source||'')+'
'+escHtml(c.pan||'—')+''+escHtml(c.mobile||'—')+''+escHtml(c.city||'—')+''+bd(escHtml((c.rm||'—').split(' ')[0]),'bl')+''+bd(escHtml(c.accountStatus||'Account Open'),(c.accountStatus==='Not Open'?'rd':(c.accountStatus==='Account Opening WIP'?'am':'gr')))+''+(mf>0?fmt(mf):'—')+''+(h?bd(h,'pi'):'—')+''+(tr?bd(tr,'vi'):'—')+'';}); T('cTbl').innerHTML=html+''; T('cPagi').innerHTML='Page '+cPage+' of '+pages+' · '+total+' records'; }; renderProductWiseTab=function(){ var q=(T('pwSrch')?T('pwSrch').value:'').toLowerCase(); var rows=allVisibleProductRows().filter(function(r){var t=[r.client,r.pan,r.mobile,r.rm,r.product,r.scheme,r.folio,r.status,r.source].join(' ').toLowerCase();return !q||t.indexOf(q)>=0;}); var mfRows=rows.filter(function(r){return ocProductKind(r)==='mf';}), healthRows=rows.filter(function(r){return ocProductKind(r)==='health';}), termRows=rows.filter(function(r){return ocProductKind(r)==='term';}); var sum=function(a){return a.reduce(function(x,r){return x+(Number(r.amount)||0);},0);}; T('pwKpi').innerHTML=[['Total Records',rows.length,'#1B4FD8'],['MF SIP',fmt(sum(mfRows)),'#16a34a'],['Health Insurance',healthRows.length+' / '+fmt(sum(healthRows)),'#EC4899'],['Term Insurance',termRows.length+' / '+fmt(sum(termRows)),'#7C3AED']].map(function(k){return '
'+k[0]+'
'+k[1]+'
';}).join(''); var html='ClientPANMobileRMProductScheme / PolicyFolio / Policy NoAmountFrequencyStatusSourceAction'; rows.forEach(function(r){var k=ocProductKind(r),cls=k==='health'?'pi':(k==='term'?'vi':(k==='mf'?'gr':'bl')); html+=''+escHtml(r.client)+''+escHtml(r.pan||'')+''+escHtml(r.mobile||'')+''+bd(escHtml((r.rm||'').split(' ')[0]),'bl')+''+bd(escHtml(r.product||''),cls)+''+escHtml(r.scheme||'')+''+escHtml(r.folio||'')+''+fmt(r.amount)+''+escHtml(r.frequency||'')+''+bd(escHtml(r.status||''),String(r.status)==='Active'?'gr':(String(r.status)==='Expired'?'rd':'am'))+''+escHtml(r.source||'')+''+(r.source==='Manual'?' ':'')+'';}); T('pwTbl').innerHTML=html+''; }; renderProductWiseInvestment=function(id,cF,cS,cI){ var rows=rowsForClient(id); var mf=rows.filter(function(r){return ocProductKind(r)==='mf';}), term=rows.filter(function(r){return ocProductKind(r)==='term';}), health=rows.filter(function(r){return ocProductKind(r)==='health';}), other=rows.filter(function(r){return ocProductKind(r)==='other';}); var groups=[['Mutual Fund SIP',mf,'MF','bl'],['Health Insurance',health,'Health','pi'],['Term Insurance',term,'Term','vi'],['Other Products',other,'Other','am']].filter(function(g){return g[1].length;}); if(!groups.length)groups=[['No Product',[], 'Pending','rd']]; var html='
💼 Product Wise Investment
'; groups.forEach(function(g){var amt=g[1].reduce(function(a,r){return a+(Number(r.amount)||0);},0); html+='';}); html+='
ProductRecordsInvestment / PremiumDetails
'+bd(g[2],g[3])+' '+g[0]+''+g[1].length+''+fmt(amt)+''+g[1].slice(0,3).map(function(r){return escHtml(r.scheme||r.folio||'—');}).join('
')+'
'; return html; }; /* === FINAL PATCH: login + Priya insurance + dd-mm-yyyy email + HTML preview/outlook === */ (function(){ function safeT(id){return document.getElementById(id)} window.toDMY=function(v){ if(!v) return '—'; var s=String(v).trim(); var m=s.match(/^(\d{4})-(\d{1,2})-(\d{1,2})/); if(m) return (m[3].padStart(2,'0')+'-'+m[2].padStart(2,'0')+'-'+m[1]); var d=new Date(s); if(!isNaN(d)) return String(d.getDate()).padStart(2,'0')+'-'+String(d.getMonth()+1).padStart(2,'0')+'-'+d.getFullYear(); return s; }; window.getClientById=function(id){return CLIENTS.filter(function(c){return String(c.id)===String(id);})[0]||{};}; window.firstSIP=function(c){return SIPS.filter(function(s){return String(s.clientId)===String(c.id);})[0]||{};}; window.firstIns=function(c,kind){ var arr=INSURANCE.filter(function(i){return String(i.clientId)===String(c.id);}); if(kind==='term') arr=arr.filter(function(i){return String(i.type+' '+i.policy).toLowerCase().indexOf('term')>=0;}); if(kind==='health') arr=arr.filter(function(i){return String(i.type+' '+i.policy).toLowerCase().indexOf('term')<0;}); return arr[0]||{}; }; try{ if(!USERS.some(function(u){return u.u==='priya.gaonkar';})) USERS.push({u:'priya.gaonkar',p:'rm123',role:'RM',name:'Priya Gaonkar',rm:'Priya Gaonkar'}); if(!USERS.some(function(u){return u.u==='priya';})) USERS.push({u:'priya',p:'rm123',role:'RM',name:'Priya Gaonkar',rm:'Priya Gaonkar'}); }catch(e){} window.doLogin=function(){ var u=(safeT('lU')&&safeT('lU').value||'').trim(); var p=(safeT('lP')&&safeT('lP').value||'').trim(); if(!u||!p){safeT('lErr').textContent='Please enter username and password.';safeT('lErr').style.display='block';return;} var user=(USERS||[]).filter(function(x){return x.u.toLowerCase()===u.toLowerCase() && x.p===p && x.role===selRole;})[0] || (USERS||[]).filter(function(x){return x.u.toLowerCase()===u.toLowerCase() && x.p===p;})[0]; if(!user){safeT('lErr').textContent='Invalid username or password. Try admin/admin123 or priya.gaonkar/rm123';safeT('lErr').style.display='block';return;} selRole=user.role; if(typeof setRole==='function') setRole(user.role); safeT('lErr').style.display='none'; CU=user; safeT('LP').style.display='none'; safeT('SB').style.display='flex'; safeT('MN').style.display='block'; safeT('sbNm').textContent=user.name; safeT('sbRl').textContent=user.role; buildNav(); goPage('dashboard'); }; var oldFill=window.fillBody; window.fillBody=function(tmplKey, client){ client=client||{}; var sip=firstSIP(client), health=firstIns(client,'health'), term=firstIns(client,'term'), anyIns=firstIns(client,''); var b=(ETMPLS[tmplKey]&&ETMPLS[tmplKey].body)||''; var amount=sip.sipAmount || anyIns.premium || ''; var scheme=sip.scheme || anyIns.policy || 'your plan'; var date=sip.endDate || anyIns.renewalDate || ''; if(tmplKey==='Health Insurance' || tmplKey==='Insurance Renewal'){ scheme=health.policy || anyIns.policy || 'Health Insurance'; amount=health.premium || anyIns.premium || ''; date=health.renewalDate || anyIns.renewalDate || ''; b='Dear {{NAME}},\n\nYour Health Insurance details are mentioned below:\n\nPolicy: {{SCHEME}}\nPolicy No: '+(health.policyNo||anyIns.policyNo||'—')+'\nSum Insured / Premium: ₹{{AMT}}\nRenewal Date: {{DATE}}\n\nPlease review the policy and renew before due date to keep your family protected.\n\nFor assistance, contact your Relationship Manager: {{RM}}\n\nWarm regards,\nTeam ONE CALL Financial Services'; } if(tmplKey==='Term Insurance'){ scheme=term.policy || 'Term Insurance Plan'; amount=term.premium || ''; date=term.renewalDate || ''; b='Dear {{NAME}},\n\nYour Term Insurance / protection planning details are mentioned below:\n\nPlan: {{SCHEME}}\nPolicy No: '+(term.policyNo||'—')+'\nCover / Premium: ₹{{AMT}}\nReview / Renewal Date: {{DATE}}\n\nTerm insurance helps secure your family\'s future with high coverage at affordable cost.\n\nFor assistance, contact your Relationship Manager: {{RM}}\n\nWarm regards,\nTeam ONE CALL Financial Services'; } return b.replace(/{{NAME}}/g, client.name||'Valued Client') .replace(/{{RM}}/g, client.rm||'Your Relationship Manager') .replace(/{{AMT}}/g, amount ? Number(amount).toLocaleString('en-IN') : '—') .replace(/{{SCHEME}}/g, scheme||'—') .replace(/{{DATE}}/g, toDMY(date)); }; window.buildOutlookHtml=function(subject, bodyText, ico){ var lsrc=(document.querySelector('#sbLogo')&&document.querySelector('#sbLogo').src)||''; return '
'+ '
'+ '
ONE CALL Financial Services
CLIENT COMMUNICATION
'+ '

'+(ico||'')+' '+subject+'

'+bodyText.split('\n').map(function(x){return x.replace(/&/g,'&').replace(//g,'>');}).join('
')+'
ONE CALL Financial Services
Mumbai, Maharashtra | info@onecallfinancial.com | +91 98765 43210
'; }; window.outlookOpen=function(email, subject, body){ var url='https://mail.google.com/mail/?view=cm&fs=1&to='+encodeURIComponent(email||'')+'&su='+encodeURIComponent(subject||'')+'&body='+encodeURIComponent(body||''); window.open(url,'_blank','noopener'); }; var oldRenderDash=window.renderDash; window.renderDash=function(){ oldRenderDash(); try{ var cl=visCL(), ins=visINS(), sips=visSIP().filter(function(s){return s.status==='Active';}); var rms=[...new Set(cl.map(function(c){return c.rm||'Unassigned';}))]; if(rms.length){ var max=Math.max.apply(null,rms.map(function(r){return Math.max(1,sips.filter(function(s){return (getClientById(s.clientId).rm||'Unassigned')===r;}).reduce(function(a,x){return a+(Number(x.sipAmount)||0);},0), ins.filter(function(i){return (getClientById(i.clientId).rm||i.rm||'Unassigned')===r;}).reduce(function(a,x){return a+(Number(x.premium)||0);},0));})); safeT('rmBars').innerHTML=rms.map(function(r){ var sipAmt=sips.filter(function(s){return (getClientById(s.clientId).rm||'Unassigned')===r;}).reduce(function(a,x){return a+(Number(x.sipAmount)||0);},0); var iRows=ins.filter(function(i){return (getClientById(i.clientId).rm||i.rm||'Unassigned')===r;}); var iAmt=iRows.reduce(function(a,x){return a+(Number(x.premium)||0);},0); var label=sipAmt>0 ? fmt(sipAmt)+'/mo' : (iRows.length+' Insurance · '+fmt(iAmt)); var pct=Math.round(Math.max(sipAmt,iAmt)/max*100); return '
'+escHtml(r)+''+cl.filter(function(c){return (c.rm||'Unassigned')===r;}).length+'c · '+label+'
'; }).join(''); } }catch(e){} }; var oldEP=window.renderEP; window.renderEP=function(cl){ oldEP(cl); try{ var tmpl=ETMPLS[selTmpl]; var pc=(selRecip==='all'?cl[0]:cl.filter(function(c){return c.id===selRecip;})[0])||cl[0]||{}; var body=fillBody(selTmpl,pc); var html=buildOutlookHtml(tmpl.sub,body,tmpl.ico); if(safeT('tmplPrev')) safeT('tmplPrev').innerHTML=safeT('tmplPrev').innerHTML + '
'; }catch(e){} }; })(); /* === FINAL FIX PATCH: Outlook HTML, dd-mm-yyyy dates, sorted alerts, instant menu === */ (function(){ function $(id){return document.getElementById(id)} function ehtml(s){return String(s==null?'':s).replace(/[&<>\"]/g,function(c){return {'&':'&','<':'<','>':'>','\"':'"'}[c]})} window.toDMY = function(s){ if(!s) return '—'; var m=String(s).match(/^(\d{4})-(\d{2})-(\d{2})/); if(m) return m[3]+'-'+m[2]+'-'+m[1]; var d=new Date(s); if(!isNaN(d)) return String(d.getDate()).padStart(2,'0')+'-'+String(d.getMonth()+1).padStart(2,'0')+'-'+d.getFullYear(); return String(s); }; function logoSrc(){var im=document.querySelector('#sbLogo')||document.querySelector('.llogo'); return im?im.src:'';} function emailHtml(subject, bodyText, ico){ var lines=String(bodyText||'').split('\n').map(function(x){return ehtml(x)}).join('
'); return ''+ '
'+ ''+ ''+ ''+ '
'+ ''+ '
ONE CALL Financial Services
CLIENT COMMUNICATION
'+ '
'+ehtml(ico||'')+' '+ehtml(subject||'')+'
'+lines+'
'+ '
ONE CALL Financial Services
Mumbai, Maharashtra | info@onecallfinancial.com | +91 98765 43210
'; } window.buildOutlookHtml=emailHtml; function makeEml(to, subject, html){ var nl='\r\n', b='----ONECALL_'+Date.now(); var eml='To: '+(to||'')+nl+'Subject: '+(subject||'')+nl+'MIME-Version: 1.0'+nl+'Content-Type: multipart/alternative; boundary="'+b+'"'+nl+nl+ '--'+b+nl+'Content-Type: text/html; charset=UTF-8'+nl+'Content-Transfer-Encoding: 8bit'+nl+nl+html+nl+'--'+b+'--'; var blob=new Blob([eml],{type:'message/rfc822'}), url=URL.createObjectURL(blob), a=document.createElement('a'); a.href=url; a.download=(subject||'ONE_CALL_Email').replace(/[\\/:*?"<>|]/g,'_')+'.eml'; document.body.appendChild(a); a.click(); setTimeout(function(){URL.revokeObjectURL(url);a.remove()},1200); } window.outlookOpen=function(email, subject, body){ var _k=(typeof selTmpl!=='undefined'&&selTmpl)||window.selTmpl||''; var ico=(window.ETMPLS&&ETMPLS[_k]&&ETMPLS[_k].ico)||''; var html=emailHtml(subject, body, ico); if(!email){ alert('Is client ka email address nahi hai — pehle email add karo.'); return; } if(!confirm('Email bhejna hai?\n\nTo: '+email+'\nSubject: '+subject)) return; var API = 'http://187.77.189.199:8006/send'; fetch(API, { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({to:email, subject:subject||'', html:html, text:body||''}) }).then(function(r){ return r.json().catch(function(){ return {ok:false, error:'Server response invalid'}; }); }) .then(function(j){ if(j.ok){ alert('✅ Email bhej diya gaya: '+email); } else { alert('❌ Email nahi gaya: '+(j.error||'unknown error')); } }).catch(function(err){ alert('❌ Email server (port 8006) se connect nahi ho paya.\n\nServer chal raha hai ya nahi check karo.\n\n('+err.message+')'); }); }; window.fillBody=function(tmplKey, client){ client=client||{}; var tmpl=(ETMPLS&&ETMPLS[tmplKey])||{body:''}; var s=(typeof firstSIP==='function'?firstSIP(client):{})||{}, h=(typeof firstIns==='function'?firstIns(client,'health'):{})||{}, trm=(typeof firstIns==='function'?firstIns(client,'term'):{})||{}, any=(typeof firstIns==='function'?firstIns(client,''):{})||{}; var body=tmpl.body, amount=s.sipAmount||any.premium||'', scheme=s.scheme||any.policy||'your plan', date=s.endDate||any.renewalDate||''; if(tmplKey==='Health Insurance' || tmplKey==='Insurance Renewal'){ scheme=h.policy||any.policy||'Health Insurance'; amount=h.premium||any.premium||''; date=h.renewalDate||any.renewalDate||''; body='Dear {{NAME}},\n\nYour Health Insurance policy details are mentioned below:\n\nPolicy: {{SCHEME}}\nPolicy No: '+(h.policyNo||any.policyNo||'—')+'\nPremium: ₹{{AMT}}\nRenewal Date: {{DATE}}\n\nPlease renew before the due date to keep your family protected and avoid policy lapse.\n\nFor assistance, contact your Relationship Manager: {{RM}}\n\nWarm regards,\nTeam ONE CALL Financial Services'; } if(tmplKey==='Term Insurance'){ scheme=trm.policy||'Term Insurance Plan'; amount=trm.premium||''; date=trm.renewalDate||''; body='Dear {{NAME}},\n\nYour Term Insurance / protection planning details are mentioned below:\n\nPlan: {{SCHEME}}\nPolicy No: '+(trm.policyNo||'—')+'\nPremium / Cover Reference: ₹{{AMT}}\nReview / Renewal Date: {{DATE}}\n\nTerm insurance helps secure your family\'s financial future with high coverage at affordable cost.\n\nFor assistance, contact your Relationship Manager: {{RM}}\n\nWarm regards,\nTeam ONE CALL Financial Services'; } return body.replace(/{{NAME}}/g,client.name||'Valued Client').replace(/{{RM}}/g,client.rm||'Your Relationship Manager').replace(/{{AMT}}/g,amount?Number(amount).toLocaleString('en-IN'):'—').replace(/{{SCHEME}}/g,scheme||'—').replace(/{{DATE}}/g,toDMY(date)); }; window.sipEmail=function(cid,scheme,amt,endDate){ var c=(CLIENTS||[]).filter(function(x){return x.id===cid})[0]; if(!c) return; window.selTmpl='SIP Expiring'; var body=ETMPLS['SIP Expiring'].body.replace(/{{NAME}}/g,c.name||'').replace(/{{RM}}/g,c.rm||'').replace(/{{AMT}}/g,(amt||0).toLocaleString('en-IN')).replace(/{{SCHEME}}/g,scheme||'').replace(/{{DATE}}/g,toDMY(endDate)); outlookOpen(c.email||'',ETMPLS['SIP Expiring'].sub,body); }; window.insEmail=function(cid){var c=(CLIENTS||[]).filter(function(x){return x.id===cid})[0]; if(!c)return; try{selTmpl='Insurance Renewal';}catch(e){} window.selTmpl='Insurance Renewal'; outlookOpen(c.email||'',ETMPLS['Insurance Renewal'].sub,fillBody('Insurance Renewal',c));}; window.bdSend=function(cid,lang){var c=(CLIENTS||[]).filter(function(x){return x.id===cid})[0]; if(!c)return; var key=(lang==='mr'?'Birthday Marathi':'Birthday English'); try{selTmpl=key;}catch(e){} window.selTmpl=key; outlookOpen(c.email||'',ETMPLS[key].sub,fillBody(key,c));}; window.renderEP=function(cl){ cl=cl||visCL(); var tmpl=ETMPLS[selTmpl], pc=(selRecip==='all'?cl[0]:cl.filter(function(c){return c.id===selRecip})[0])||cl[0]||{}; var opts=''; cl.slice(0,400).forEach(function(c){opts+=''}); $('tmplList').innerHTML='
Templates ('+Object.keys(ETMPLS).length+')
'+Object.keys(ETMPLS).map(function(k){return ''+ETMPLS[k].ico+' '+k+''}).join(''); var body=fillBody(selTmpl,pc), html=emailHtml(tmpl.sub,body,tmpl.ico); $('tmplPrev').innerHTML='
'+tmpl.ico+' '+selTmpl+'
Subject: '+tmpl.sub+'
'+html; }; window.doSend=function(){var cl=visCL(), tmpl=ETMPLS[selTmpl], c=(selRecip==='all'?cl[0]:cl.filter(function(x){return x.id===selRecip})[0]); if(!c)return; outlookOpen(c.email||'',tmpl.sub,fillBody(selTmpl,c));}; window.renderAl=function(tab){ alTab=tab||alTab||'sip'; var cl=visCL(), sips=visSIP(), ins=visINS(), act=sips.filter(function(s){return s.status==='Active'}); var sipAll=act.filter(function(s){var d=daysDiff(s.endDate);return s.endDate&&d>=0&&d<=60}).sort(function(a,b){return daysDiff(a.endDate)-daysDiff(b.endDate)}); var sipXp=sips.filter(function(s){return s.endDate&&daysDiff(s.endDate)<0}).sort(function(a,b){return daysDiff(b.endDate)-daysDiff(a.endDate)}); var insDue=ins.filter(function(i){var d=daysDiff(i.renewalDate);return i.renewalDate&&d>=0&&d<=60}).sort(function(a,b){return daysDiff(a.renewalDate)-daysDiff(b.renewalDate)}); var insXp=ins.filter(function(i){return i.renewalDate&&daysDiff(i.renewalDate)<0}); function bdIn(c,n1,n2){try{var d=new Date(c.dob); d.setFullYear(today.getFullYear()); var diff=Math.floor((d-today)/86400000); return diff>=n1&&diff<=n2}catch(e){return false}} var bdT=cl.filter(function(c){return bdIn(c,0,0)}), bdTom=cl.filter(function(c){return bdIn(c,1,1)}), bdWk=cl.filter(function(c){return bdIn(c,0,7)}); var noSIP=cl.filter(function(c){return !act.some(function(s){return s.clientId===c.id})}); $('alTabs').innerHTML=[['sip','SIP Alerts',sipAll.length+sipXp.length],['insurance','Insurance 🏥',insDue.length+insXp.length],['birthday','Birthdays 🎂',bdT.length+bdTom.length],['clients','Client Alerts',noSIP.length]].map(function(t){return ''}).join(''); function sec(title,rows,cols){return '
'+title+' '+rows.length+'
'+(rows.length?'
'+cols+''+rows.join('')+'
':'
No records
')+'
'} function srow(s){var c=(CLIENTS||[]).filter(function(x){return x.id===s.clientId})[0]||{}, d=daysDiff(s.endDate); return ''+ehtml(c.name||'—')+''+ehtml(s.scheme||'—')+''+(c.mobile||'—')+''+bd(((c.rm||'—').split(' ')[0]),'bl')+'₹'+Number(s.sipAmount||0).toLocaleString('en-IN')+'/mo'+toDMY(s.endDate)+'⚠️ '+Math.abs(d)+'d '+(d<0?'ago':'left')+''} function irow(i){var c=(CLIENTS||[]).filter(function(x){return x.id===i.clientId})[0]||{}, d=daysDiff(i.renewalDate), typ=(String(i.type||i.product||i.policy||'').toLowerCase().indexOf('term')>=0?'Term':'Health'); return ''+ehtml(c.name||'—')+''+typ+''+ehtml(i.policy||'—')+''+(c.mobile||'—')+''+bd(((c.rm||'—').split(' ')[0]),'bl')+''+fmt(i.premium)+''+toDMY(i.renewalDate)+''+(d<0?'Expired':'⚠️ '+d+'d left')+''} function brow(c){return ''+ehtml(c.name||'—')+''+(c.mobile||'—')+''+(c.email||'—')+''+toDMY(c.dob)+''+bd(((c.rm||'—').split(' ')[0]),'bl')+' '} var cs='ClientSchemeMobileRMSIP AmtEnd DateStatusOutlook', ci='ClientTypePolicyMobileRMPremiumRenewalStatusOutlook', cb='ClientMobileEmailDOBRMSend'; if(alTab==='sip'){ var groups={}; sipAll.forEach(function(s){var d=daysDiff(s.endDate); (groups[d]=groups[d]||[]).push(s)}); var html=Object.keys(groups).sort(function(a,b){return a-b}).map(function(k){return sec('🔴 '+k+' Days Left', groups[k].map(srow), cs)}).join('')+sec('⚫ Expired SIPs',sipXp.slice(0,80).map(srow),cs); $('alContent').innerHTML=html; } else if(alTab==='insurance'){ var h=insDue.filter(function(i){return String(i.type||i.product||i.policy||'').toLowerCase().indexOf('term')<0}), t=insDue.filter(function(i){return String(i.type||i.product||i.policy||'').toLowerCase().indexOf('term')>=0}); $('alContent').innerHTML=sec('🏥 Health Insurance Renewal',h.map(irow),ci)+sec('🛡️ Term Insurance Renewal',t.map(irow),ci)+sec('⚫ Expired Insurance',insXp.map(irow),ci); } else if(alTab==='birthday') $('alContent').innerHTML=sec('🎂 Today',bdT.map(brow),cb)+sec('🎈 Tomorrow',bdTom.map(brow),cb)+sec('📅 This Week',bdWk.map(brow),cb); else $('alContent').innerHTML=sec('⚠️ No Active SIP', noSIP.map(function(c){return ''+ehtml(c.name||'—')+''+(c.pan||'—')+''+(c.mobile||'—')+''+(c.city||'—')+''+bd(((c.rm||'—').split(' ')[0]),'bl')+''}), 'ClientPANMobileCityRM'); }; var oldGo=window.goPage; window.goPage=function(p){try{oldGo(p); setTimeout(function(){ if(p==='alerts')renderAl(alTab||'sip'); if(p==='email')renderEmail();},0)}catch(e){console.error(e)}}; })(); // ════════════════════════════════════════════════ // IMPORT DATA (Excel upload — replaces old data) // ════════════════════════════════════════════════ function renderImport(){ var st = T('impStatus'); if(window.__IMPORTED){ st.style.color = '#0a7d38'; st.textContent = '✅ Abhi IMPORTED data chal raha hai' + (typeof window.__IMPORTED==='string' ? ' (uploaded: '+window.__IMPORTED+')' : '') + ' — ' + CLIENTS.length + ' clients, ' + SIPS.length + ' SIPs, ' + FOLIOS.length + ' folios.'; } else { st.style.color = '#345'; st.textContent = 'Abhi built-in (original) data chal raha hai — ' + CLIENTS.length + ' clients, ' + SIPS.length + ' SIPs, ' + FOLIOS.length + ' folios.'; } T('impSummary').textContent = ''; T('impSipOk').textContent = ''; T('impFolioOk').textContent = ''; } function _impClean(v){ if(v===null || v===undefined) return ''; var s = String(v).trim(); if(s==='-'||s==='nan'||s==='NaN'||s==='None') return ''; return s; } function _impPan(v){ return _impClean(v).toUpperCase(); } function _impTitle(s){ s=_impClean(s); if(!s) return ''; return s.split(/\s+/).map(function(w){ return w.charAt(0).toUpperCase()+w.slice(1).toLowerCase(); }).join(' '); } function _impISO(v){ if(v===null||v===undefined||v==='') return ''; if(v instanceof Date && !isNaN(v)) { return v.getFullYear()+'-'+String(v.getMonth()+1).padStart(2,'0')+'-'+String(v.getDate()).padStart(2,'0'); } if(typeof v==='number'){ // excel serial var d = new Date(Math.round((v-25569)*86400*1000)); if(!isNaN(d)) return d.getFullYear()+'-'+String(d.getMonth()+1).padStart(2,'0')+'-'+String(d.getDate()).padStart(2,'0'); return ''; } var s=String(v).trim(); var m=s.match(/^(\d{1,2})[-\/](\d{1,2})[-\/](\d{4})$/); // dd-mm-yyyy if(m) return m[3]+'-'+m[2].padStart(2,'0')+'-'+m[1].padStart(2,'0'); m=s.match(/^(\d{4})-(\d{1,2})-(\d{1,2})/); if(m) return m[1]+'-'+m[2].padStart(2,'0')+'-'+m[3].padStart(2,'0'); var d2=new Date(s); if(!isNaN(d2)) return d2.getFullYear()+'-'+String(d2.getMonth()+1).padStart(2,'0')+'-'+String(d2.getDate()).padStart(2,'0'); return ''; } function _impNum(v){ if(typeof v==='number') return v; var n=parseFloat(String(v||'').replace(/[,₹\s]/g,'')); return isNaN(n)?0:n; } function _readWB(file){ return new Promise(function(res,rej){ var r=new FileReader(); r.onload=function(e){ try{ res(XLSX.read(new Uint8Array(e.target.result),{type:'array',cellDates:true})); }catch(err){ rej(err); } }; r.onerror=function(){ rej(new Error('File read failed')); }; r.readAsArrayBuffer(file); }); } function _col(row, names){ // get first matching column (case/space tolerant) var keys=Object.keys(row); for(var i=0;i(prio[pan][f]||-1))){ c[f]=v; prio[pan][f]=p; } } set('name',_impTitle(name)); set('mobile',_impClean(mobile)); set('email',_impClean(email).toLowerCase()); set('dob',_impISO(dob)); set('city',_impTitle(city)); set('pincode',_impClean(pincode).replace(/\.0$/,'')); set('rm',_impTitle(rm)); set('address',_impClean(address)); } rowsF.forEach(function(r){ upsert(_impPan(_col(r,['First Holder PAN'])), _col(r,['Investor Name']), _col(r,['Mobile No']), _col(r,['Email']), _col(r,['First holder DOB']), _col(r,['City']), _col(r,['Pin code']), _col(r,['Partner/ Employee','Partner/Employee']), _col(r,['Address']), 2); }); rowsS.forEach(function(r){ upsert(_impPan(_col(r,['PAN NO'])), _col(r,['Investor']), _col(r,['Mobile No']), _col(r,['E-MAIL ID','EMAIL']), _col(r,['DOB']), _col(r,['CITY']), _col(r,['PINCODE']), _col(r,['Partner/Employee','Partner/ Employee']), _col(r,['ADDRESS']), 1); }); var pans=Object.keys(cmap).sort(function(a,b){ return (cmap[a].name||'').localeCompare(cmap[b].name||''); }); var newClients=[], panId={}; pans.forEach(function(p,i){ panId[p]=i+1; var c=cmap[p]; newClients.push({id:i+1,pan:p,name:c.name,mobile:c.mobile,email:c.email,dob:c.dob,city:c.city,pincode:c.pincode,rm:c.rm,address:c.address}); }); // ── SIPs ── var t=new Date(); t.setHours(0,0,0,0); var newSips=[]; rowsS.forEach(function(r){ var pan=_impPan(_col(r,['PAN NO'])); if(!pan||!panId[pan]) return; var end=_impISO(_col(r,['End Date'])); var status='Active'; if(end){ var d=new Date(end); if(!isNaN(d)&&d"']/g, function(ch){ return {'&':'&','<':'<','>':'>','"':'"',"'":'''}[ch]; }); } function clientList(){ return typeof visCL === 'function' ? visCL() : (CLIENTS || []); } function exactClient(id){ return clientList().filter(function(c){ return String(c.id) === String(id); })[0] || null; } function validEmail(v){ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(v || '').trim()); } function dmy(v){ if(!v) return '—'; var s=String(v).trim(), m=s.match(/^(\d{4})-(\d{1,2})-(\d{1,2})/); if(m) return m[3].padStart(2,'0')+'-'+m[2].padStart(2,'0')+'-'+m[1]; var d=new Date(s); return isNaN(d) ? s : String(d.getDate()).padStart(2,'0')+'-'+String(d.getMonth()+1).padStart(2,'0')+'-'+d.getFullYear(); } function number(v){ return Number(v || 0).toLocaleString('en-IN'); } function byUpcomingDate(a, field){ return a.slice().sort(function(x,y){ var xd=new Date(x[field] || '2999-12-31'), yd=new Date(y[field] || '2999-12-31'); return xd-yd; }); } function clientSip(c, expiring){ var rows=(SIPS || []).filter(function(s){ return String(s.clientId)===String(c.id); }); if(expiring) rows=rows.filter(function(s){ return s.endDate; }); else { var active=rows.filter(function(s){ return String(s.status).toLowerCase()==='active'; }); if(active.length) rows=active; } return byUpcomingDate(rows,'endDate')[0] || {}; } function clientInsurance(c, term){ var rows=(INSURANCE || []).filter(function(i){ return String(i.clientId)===String(c.id); }); rows=rows.filter(function(i){ var isTerm=String((i.type||'')+' '+(i.policy||'')).toLowerCase().indexOf('term')>=0; return term===null ? true : isTerm===term; }); return byUpcomingDate(rows,'renewalDate')[0] || {}; } function templateData(key,c){ var sip=clientSip(c,key==='SIP Expiring'); var health=clientInsurance(c,false), term=clientInsurance(c,true); var d={name:c.name||'Valued Client',rm:c.rm||'Your Relationship Manager',amount:'—',scheme:'—',date:'—',policyNo:'—'}; if(key==='SIP Renewal'||key==='SIP Expiring'){ d.amount=sip.sipAmount ? number(sip.sipAmount) : '—'; d.scheme=sip.scheme||'—'; d.date=dmy(sip.endDate); d.folio=sip.folio||'—'; } else if(key==='Health Insurance'||key==='Insurance Renewal'){ d.amount=health.premium ? number(health.premium) : '—'; d.scheme=health.policy||'Health Insurance'; d.date=dmy(health.renewalDate); d.policyNo=health.policyNo||'—'; } else if(key==='Term Insurance'){ d.amount=term.premium ? number(term.premium) : '—'; d.scheme=term.policy||'Term Insurance'; d.date=dmy(term.renewalDate); d.policyNo=term.policyNo||'—'; } return d; } function replaceTokens(text,d){ return String(text||'') .replace(/\{\{NAME\}\}/g,d.name).replace(/\{\{RM\}\}/g,d.rm) .replace(/\{\{AMT\}\}/g,d.amount).replace(/\{\{SCHEME\}\}/g,d.scheme) .replace(/\{\{DATE\}\}/g,d.date).replace(/\{\{POLICY_NO\}\}/g,d.policyNo||'—') .replace(/\{\{FOLIO\}\}/g,d.folio||'—'); } window.fillBody=function(key,c){ c=c||{}; var t=ETMPLS[key]||{body:''}, d=templateData(key,c), body=t.body; if(key==='Health Insurance'||key==='Insurance Renewal'){ body='Dear {{NAME}},\n\nThis is a reminder regarding your health insurance policy:\n\nPolicy: {{SCHEME}}\nPolicy Number: {{POLICY_NO}}\nSum Insured / Premium Reference: ₹{{AMT}}\nRenewal Date: {{DATE}}\n\nPlease review and renew the policy before the due date so that your family’s protection continues without interruption.\n\nFor any assistance, please contact your Relationship Manager, {{RM}}.\n\nWarm regards,\nTeam ONE CALL Financial Services'; } else if(key==='Term Insurance'){ body='Dear {{NAME}},\n\nPlease find your term insurance review details below:\n\nPlan: {{SCHEME}}\nPolicy Number: {{POLICY_NO}}\nCover / Premium Reference: ₹{{AMT}}\nReview / Renewal Date: {{DATE}}\n\nA timely review helps ensure that your family’s financial protection remains aligned with your current needs.\n\nFor any assistance, please contact your Relationship Manager, {{RM}}.\n\nWarm regards,\nTeam ONE CALL Financial Services'; } return replaceTokens(body,d); }; function emailLogo(){ var im=document.getElementById('sbLogo')||document.querySelector('.llogo'); return im ? im.src : ''; } window.buildOutlookHtml=function(subject,bodyText,ico){ var paragraphs=String(bodyText||'').split(/\n{2,}/).map(function(p){ return '

'+ p.split('\n').map(eh).join('
')+'

'; }).join(''); return ''+ ''+ '
'+ ''+ ''+ ''+ '
'+ (emailLogo()?'ONE CALL logo':'')+ '
'+EMAIL_BRAND.name+'
'+ '
'+EMAIL_BRAND.tagline+'
'+eh(ico||'')+' '+eh(subject)+'
'+paragraphs+'
'+ '
'+EMAIL_BRAND.name+'
'+ '
'+eh(EMAIL_BRAND.tagline)+'
'+ ''+eh(EMAIL_BRAND.website)+'  •  '+eh(EMAIL_BRAND.replyEmail)+'
'+ '
This communication is intended only for the named recipient. Investment values and dates should be verified with your Relationship Manager before taking action.
'+ '
'; }; function getLog(){ try{return JSON.parse(localStorage.getItem('ONECALL_EMAIL_SENT_LOG')||'[]');}catch(e){return [];} } function addLog(row){ var a=getLog(); a.push(row); if(a.length>100)a=a.slice(-100); localStorage.setItem('ONECALL_EMAIL_SENT_LOG',JSON.stringify(a)); } function emailApi(){ if(window.ONECALL_EMAIL_API) return window.ONECALL_EMAIL_API; if(location.protocol.indexOf('http')===0 && location.hostname==='onecallcrm.duckdns.org') return location.origin+'/send'; return 'http://187.77.189.199:8006/send'; } window.renderEP=function(cl){ cl=cl||clientList(); var tmpl=ETMPLS[selTmpl]; if(selRecip==='all' || !exactClient(selRecip)) selRecip=''; var pc=exactClient(selRecip); var opts=''; cl.slice().sort(function(a,b){return String(a.name||'').localeCompare(String(b.name||''));}).forEach(function(c){ opts+=''; }); var preview=pc ? buildOutlookHtml(tmpl.sub,fillBody(selTmpl,pc),tmpl.ico) : '
✉️
Preview ke liye ek client select karein
Email client select kiye bina send nahi hoga.
'; T('tmplPrev').innerHTML= '
'+ '
'+tmpl.ico+' '+eh(selTmpl)+'
'+ '
Subject: '+eh(tmpl.sub)+'
'+ (pc?'
Recipient locked: '+eh(pc.name)+' <'+eh(pc.email||'Email missing')+'> · RM: '+eh(pc.rm||'—')+'
':'')+'
'+ '
'+ '
'+preview; var log=getLog(); if(log.length){ T('sentLog').style.display='block'; T('sentLog').innerHTML='
📋 Successful Email Log ('+log.length+')
'+ log.slice(-10).reverse().map(function(s){return '
'+eh(s.name)+' · '+eh(s.email)+'✅ '+eh(s.template)+' · '+eh(s.time)+'
';}).join(''); } else T('sentLog').style.display='none'; }; window.doSend=function(){ var c=exactClient(selRecip), t=ETMPLS[selTmpl]; if(!c){alert('Pehle ek client select karein.');return;} if(!validEmail(c.email)){alert(c.name+' ka valid email address available nahi hai. Client Master mein email update karein.');return;} var body=fillBody(selTmpl,c), html=buildOutlookHtml(t.sub,body,t.ico); if(!confirm('Please verify before sending:\n\nClient: '+c.name+'\nTo: '+c.email+'\nRM: '+(c.rm||'—')+'\nTemplate: '+selTmpl+'\nSubject: '+t.sub+'\n\nIsi client ko email send karna hai?'))return; var btn=T('tmplPrev')&&T('tmplPrev').querySelector('button.btn.bp'); if(btn){btn.disabled=true;btn.textContent='Sending…';} fetch(emailApi(),{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({to:String(c.email).trim(),subject:t.sub,html:html,text:body})}) .then(function(r){return r.json().catch(function(){return {ok:false,error:'Invalid server response'};});}) .then(function(j){ if(!j.ok)throw new Error(j.error||'Email server rejected the request'); addLog({clientId:c.id,name:c.name,email:c.email,rm:c.rm||'',template:selTmpl,subject:t.sub,time:new Date().toLocaleString('en-IN')}); alert('✅ Email successfully sent.\n\nClient: '+c.name+'\nTo: '+c.email); renderEmail(); }).catch(function(err){ alert('❌ Email send nahi hua.\n\nClient: '+c.name+'\nTo: '+c.email+'\nReason: '+err.message); if(btn){btn.disabled=false;btn.textContent='📨 Review & Send';} }); }; })(); // ════════════════════════════════════════════════ // VALUATION REPORT — upload, match, preview & email // ════════════════════════════════════════════════ var VAL_STATE={fileName:'',reportTitle:'',headers:[],rows:[],groups:[],selected:'',sending:false}; function valEsc(v){return String(v==null?'':v).replace(/[&<>"']/g,function(c){return {'&':'&','<':'<','>':'>','"':'"',"'":'''}[c];});} function valNorm(v){return String(v||'').toLowerCase().replace(/\b(mr|mrs|ms|dr|shri|smt)\.?\b/g,' ').replace(/[^a-z0-9]/g,'').trim();} function valClients(){return typeof visCL==='function'?visCL():(CLIENTS||[]);} function valEmailOk(v){return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(v||'').trim());} function valApis(){var a=[];if(window.ONECALL_EMAIL_API)a.push(window.ONECALL_EMAIL_API);if(location.protocol.indexOf('http')===0)a.push(location.origin+'/send');a.push('http://127.0.0.1:8006/send');a.push('http://localhost:8006/send');return a.filter(function(v,i,x){return v&&x.indexOf(v)===i;});} function valClientById(id){return valClients().filter(function(c){return String(c.id)===String(id);})[0]||null;} function valLogRead(){try{return JSON.parse(localStorage.getItem('ONECALL_VALUATION_LOG')||'[]');}catch(e){return [];}} function valLogAdd(x){var a=valLogRead();a.push(x);if(a.length>200)a=a.slice(-200);localStorage.setItem('ONECALL_VALUATION_LOG',JSON.stringify(a));} function valFormatCell(v){if(v instanceof Date)return v.toLocaleDateString('en-IN');if(typeof v==='number')return v.toLocaleString('en-IN',{maximumFractionDigits:2});return String(v==null?'':v);} function loadValuationReport(file){ if(!file)return; var rd=new FileReader(); T('valStatus').innerHTML='⏳ Reading '+valEsc(file.name)+'…'; rd.onload=function(e){try{ var wb=XLSX.read(new Uint8Array(e.target.result),{type:'array',cellDates:true}); var sh=wb.Sheets[wb.SheetNames[0]], matrix=XLSX.utils.sheet_to_json(sh,{header:1,defval:'',raw:true}); if(matrix.length<2)throw new Error('Report mein data rows nahi mili.'); var width=Math.max.apply(null,matrix.map(function(r){return r.length;})); var reportTitle=String((matrix[0]||[])[0]||'Investor Wise AUM Report').trim(); var headerAt=-1; for(var hi=0;hi=0;})&&hr.some(function(v){return v.indexOf('partner')>=0||v.indexOf('employee')>=0;})){headerAt=hi;break;} } if(headerAt<0)throw new Error('Header row nahi mili. "Partner/Employee" aur "Investor" headings check karein.'); var mainHeader=(matrix[headerAt]||[]).slice(), subHeader=(matrix[headerAt+1]||[]).slice(); var headers=[]; for(var hc=0;hc=0;}); if(subLooksLikeHeader)dataAt=headerAt+2; var rows=matrix.slice(dataAt).filter(function(r){return r.some(function(x){return String(x||'').trim()!=='';});}); if(!rows.length)throw new Error('Report mein blank rows ke alawa data nahi hai.'); var clients=valClients(), byName={};clients.forEach(function(c){var k=valNorm(c.name);if(k&&!byName[k])byName[k]=[];if(k)byName[k].push(c);}); var map={};rows.forEach(function(r,idx){var nm=String(r[3]||'').trim(), key=valNorm(nm), matches=byName[key]||[], c=matches.length===1?matches[0]:null, gk=c?'id:'+c.id:'name:'+key; if(!map[gk])map[gk]={key:gk,name:nm||'(Blank name)',client:c,ambiguous:matches.length>1,rows:[],sourceRows:[]}; map[gk].rows.push(r);map[gk].sourceRows.push(idx+2); }); VAL_STATE={fileName:file.name,reportTitle:reportTitle,headers:headers,rows:rows,groups:Object.keys(map).map(function(k){return map[k];}).sort(function(a,b){return a.name.localeCompare(b.name);}),selected:'',sending:false}; T('valStatus').innerHTML='✅ '+valEsc(file.name)+' uploaded · '+rows.length.toLocaleString('en-IN')+' data rows · Header detected at Excel row '+(headerAt+1)+' · Investor matched from column D'; renderValuation(); }catch(err){VAL_STATE={fileName:'',reportTitle:'',headers:[],rows:[],groups:[],selected:'',sending:false};T('valStatus').innerHTML='❌ '+valEsc(err.message)+'';renderValuation();}}; rd.onerror=function(){T('valStatus').textContent='❌ File read nahi ho saka.';};rd.readAsArrayBuffer(file); } function clearValuationReport(){VAL_STATE={fileName:'',reportTitle:'',headers:[],rows:[],groups:[],selected:'',sending:false};if(T('valFile'))T('valFile').value='';if(T('valStatus'))T('valStatus').textContent='No report uploaded. Client name D column mein hona chahiye.';renderValuation();} function renderValuation(){ if(!T('valTbl'))return;var gs=VAL_STATE.groups||[],matched=gs.filter(function(g){return g.client;}),ready=matched.filter(function(g){return valEmailOk(g.client.email);}),unmatched=gs.length-matched.length; T('valKpi').innerHTML=[['Report Rows',VAL_STATE.rows.length,'#1B4FD8'],['Unique Clients',gs.length,'#7C3AED'],['Matched / Email Ready',matched.length+' / '+ready.length,'#16a34a'],['Unmatched',unmatched,'#EF4444']].map(function(x){return '
'+x[0]+'
'+x[1]+'
';}).join(''); T('valSendAll').disabled=!ready.length||VAL_STATE.sending; var html='Client in Report (D)RowsClient Master MatchEmailStatusAction'; if(!gs.length)html+='Upload valuation report to begin.'; gs.forEach(function(g){var c=g.client, ok=c&&valEmailOk(c.email), status=c?(ok?'Ready':'Email Missing'):(g.ambiguous?'Duplicate Name':'Not Matched'); html+=''+valEsc(g.name)+''+g.rows.length+''+(c?valEsc(c.name)+'
'+valEsc(c.pan||'')+' · '+valEsc(c.rm||'')+'':'—')+''+(c?valEsc(c.email||'—'):'—')+''+status+' '+(ok?'':'')+'';}); T('valTbl').innerHTML=html+'';renderValLog(); } function valGroup(key){key=decodeURIComponent(key);return (VAL_STATE.groups||[]).filter(function(g){return g.key===key;})[0]||null;} function valSubject(g){return 'Your Valuation Report | '+g.client.name+' | ONE CALL Financial Services';} function valBody(g){var c=g.client;return 'Dear '+c.name+',\n\nPlease find attached your latest valuation report for your review. The report contains '+g.rows.length+' record'+(g.rows.length===1?'':'s')+' mapped to your investment portfolio.\n\nWe recommend reviewing the valuation, scheme details and investment values carefully. If you need any clarification or would like to discuss portfolio rebalancing, future investments or financial planning, your Relationship Manager '+(c.rm||'from ONE CALL')+' will be happy to assist you.\n\nImportant: Valuations are market-linked and may change. Please refer to the attached report and latest official statements before taking an investment decision.\n\nWarm regards,\nTeam ONE CALL Financial Services';} function valPreviewTable(g){var hs=VAL_STATE.headers, max=Math.min(hs.length,10), out='
'+hs.slice(0,max).map(function(h){return '';}).join('')+'';g.rows.slice(0,8).forEach(function(r){out+=''+hs.slice(0,max).map(function(_,i){return '';}).join('')+'';});return out+'
'+valEsc(h)+'
'+valEsc(valFormatCell(r[i]))+'
'+(g.rows.length>8?'
Preview first 8 of '+g.rows.length+' rows. Attachment mein sabhi rows rahenge.
':'');} function valEmailTable(g){var hs=VAL_STATE.headers,start=3,max=Math.min(hs.length,10),shown=hs.slice(start,max),head=shown.map(function(h){return ''+valEsc(h)+'';}).join(''),body='';g.rows.forEach(function(r){body+=''+shown.map(function(_,j){var i=start+j;return ''+valEsc(valFormatCell(r[i]))+'';}).join('')+'';});return '
'+valEsc(VAL_STATE.reportTitle||'Investor Wise AUM Report')+'
Investor: '+valEsc(g.client.name)+' · '+g.rows.length+' record'+(g.rows.length===1?'':'s')+'
'+head+''+body+'
';} function valEmailHtml(g){var parts=valBody(g).replace(/\n\nWarm regards,\nTeam ONE CALL Financial Services\s*$/,'').split(/\n\n/),placed=[];parts.forEach(function(p,i){placed.push(p);if(i===1)placed.push('[[VALUATION_TABLE]]');});var base=buildOutlookHtml(valSubject(g),placed.join('\n\n'),'📑'),placeholder='

[[VALUATION_TABLE]]

',inline='
'+valEmailTable(g)+'
';base=base.replace(placeholder,inline);var marker='',sign='Warm regards,
Team ONE CALL Financial Services';return base.indexOf(marker)>=0?base.replace(marker,sign+marker):base;} function previewValuation(key){var g=valGroup(key);if(!g)return;VAL_STATE.selected=g.key;var c=g.client; T('valPreview').innerHTML='
📑 Email Preview — '+valEsc(g.name)+'
'+(c?'To: '+valEsc(c.email||'Email missing')+' · Subject: '+valEsc(valSubject(g)):'Client Master match nahi mila. Email send disabled.')+'
'+(c&&valEmailOk(c.email)?'':'')+'
'+(c?valEmailHtml(g):'
Client Master match nahi mila.
');T('valPreview').scrollIntoView({behavior:'smooth',block:'start'}); } function valAttachment(g){var titleRow=[VAL_STATE.reportTitle||'Investor Wise AUM Report'],aoa=[titleRow,VAL_STATE.headers].concat(g.rows),ws=XLSX.utils.aoa_to_sheet(aoa),wb=XLSX.utils.book_new();if(VAL_STATE.headers.length>1)ws['!merges']=[{s:{r:0,c:0},e:{r:0,c:VAL_STATE.headers.length-1}}];ws['!cols']=VAL_STATE.headers.map(function(h,i){var max=String(h||'').length;g.rows.forEach(function(r){max=Math.max(max,String(r[i]==null?'':r[i]).length);});return {wch:Math.min(Math.max(max+2,12),32)};});XLSX.utils.book_append_sheet(wb,ws,'Valuation');var arr=XLSX.write(wb,{bookType:'xlsx',type:'array'}),bytes=new Uint8Array(arr),bin='',step=0x8000;for(var i=0;i'+valEsc(ready[i].client.name)+'';try{await valSendRequest(ready[i]);ok++;}catch(e){fail.push(ready[i].client.name+': '+e.message);if(ok===0)break;}}VAL_STATE.sending=false;T('valStatus').innerHTML=(ok?'✅':'❌')+' Send All result: '+ok+' sent · '+fail.length+' failed'+(fail.length?'
'+fail.slice(0,10).map(valEsc).join('
'):'')+(ok===0?'
Email server unavailable hai. Server start/configure hone ke baad Send All retry karein.':'');renderValuation();} function renderValLog(){if(!T('valLog'))return;var a=valLogRead();if(!a.length){T('valLog').style.display='none';return;}T('valLog').style.display='block';T('valLog').innerHTML='
📋 Valuation Email Log
'+a.slice(-10).reverse().map(function(x){return '
'+valEsc(x.name)+' · '+valEsc(x.email)+' · '+x.rows+' rows ✅ '+valEsc(x.time)+'
';}).join('');} /* ═════════════════════════════════════════════════════════════ V11: CLIENT ENGAGEMENT + ACCESS CONTROL + TASK WORKFLOW Browser storage keys: ONECALL_MEETINGS_V11 / TASKS / ACCESS ═════════════════════════════════════════════════════════════ */ (function(){ var OC_MEET='ONECALL_MEETINGS_V11', OC_TASK='ONECALL_TASKS_V11', OC_ACCESS='ONECALL_ACCESS_V11'; var ocMeetingEdit=null, ocTaskEdit=null; var css=document.createElement('style'); css.textContent='.oc-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:11px}.oc-span2{grid-column:span 2}.oc-span3{grid-column:1/-1}.oc-actions{display:flex;gap:6px;flex-wrap:wrap}.oc-note{max-width:260px;white-space:normal;line-height:1.45}.oc-rights{display:flex;gap:8px;flex-wrap:wrap}.oc-check{display:inline-flex;align-items:center;gap:5px;padding:7px 9px;border:1px solid var(--bdr);border-radius:8px;background:#fff;font-size:11px;font-weight:650}.oc-due{color:#dc2626;font-weight:700}@media(max-width:850px){.oc-grid{grid-template-columns:1fr}.oc-span2,.oc-span3{grid-column:auto}}'; document.head.appendChild(css); function get(k,d){try{return JSON.parse(localStorage.getItem(k)||JSON.stringify(d));}catch(e){return d;}} function put(k,v){localStorage.setItem(k,JSON.stringify(v));} function e(v){return String(v==null?'':v).replace(/[&<>"']/g,function(c){return {'&':'&','<':'<','>':'>','"':'"',"'":'''}[c];});} function q(id){return document.getElementById(id);} window.q=q; function dmy(v){return v?(window.toDMY?toDMY(v):v):'—';} function isoToday(){var d=new Date();return d.getFullYear()+'-'+String(d.getMonth()+1).padStart(2,'0')+'-'+String(d.getDate()).padStart(2,'0');} function uid(){return Date.now()+Math.floor(Math.random()*10000);} function staff(){return (USERS||[]).filter(function(u){return u.role!=='Admin';});} function baseAccess(){return { 'sarika.kedari':{products:['mf'],modules:['dashboard','clients','engagement','tasks','productwise','productentry','alerts','reports','documents'],clientScope:'product'}, 'priya.gaonkar':{products:['health','term'],modules:['dashboard','clients','engagement','tasks','productwise','productentry','alerts','reports','documents'],clientScope:'product'}, 'priya':{products:['health','term'],modules:['dashboard','clients','engagement','tasks','productwise','productentry','alerts','reports','documents'],clientScope:'product'}, 'rutik.savarkar':{products:['mf','health','term','other'],modules:['dashboard','clients','engagement','tasks','productwise','productentry','alerts','reports','analytics','email','valuation','newfund','export','documents'],clientScope:'rm'}, 'satish.bangar':{products:['mf','health','term','other'],modules:['dashboard','clients','engagement','tasks','productwise','productentry','alerts','reports','analytics','email','valuation','newfund','export','documents'],clientScope:'rm'}, 'suvarna.bangar':{products:['mf','health','term','other'],modules:['dashboard','clients','engagement','tasks','productwise','productentry','alerts','reports','analytics','email','valuation','newfund','export','documents'],clientScope:'rm'}, 'emp001':{products:[],modules:['dashboard','engagement','tasks'],clientScope:'none'} };} function accessAll(){var a=get(OC_ACCESS,{}),b=baseAccess();Object.keys(b).forEach(function(k){if(!a[k])a[k]=b[k];});return a;} function right(u){if(!u||u.role==='Admin')return {products:['mf','health','term','other'],modules:['all'],clientScope:'all'};return accessAll()[u.u]||{products:[],modules:['dashboard','tasks'],clientScope:'none'};} function productRowsRaw(){try{var base=typeof productBaseRows==='function'?productBaseRows():[];var manual=typeof getPEStore==='function'?getPEStore():[];return base.concat(manual);}catch(x){return [];}} function productKind(r){return typeof ocProductKind==='function'?ocProductKind(r):'other';} function allowedClientIds(){var r=right(CU),ids={};if(!CU||CU.role==='Admin'||r.clientScope==='all')return null;if(r.clientScope==='rm'){allClientsMaster().forEach(function(c){if(c.rm===CU.rm)ids[String(c.id)]=1;});return ids;}if(r.clientScope==='none')return ids;productRowsRaw().forEach(function(x){if(r.products.indexOf(productKind(x))>=0)ids[String(x.clientId)]=1;});return ids;} try{ var su=USERS.filter(function(u){return u.u==='sarika.kedari';})[0];if(su){su.role='Employee';su.rm=null;} var pu=USERS.filter(function(u){return u.u==='priya.gaonkar';})[0];if(pu){pu.role='Employee';pu.rm=null;}else USERS.push({u:'priya.gaonkar',p:'rm123',role:'Employee',name:'Priya Gaonkar',rm:null}); var pa=USERS.filter(function(u){return u.u==='priya';})[0];if(pa){pa.role='Employee';pa.rm=null;} }catch(x){} window.ocHasModule=function(k){var r=right(CU);return !CU||CU.role==='Admin'||r.modules.indexOf('all')>=0||r.modules.indexOf(k)>=0;}; window.visCL=function(){var all=allClientsMaster(),ids=allowedClientIds();return ids===null?all:all.filter(function(c){return ids[String(c.id)];});}; window.visSIP=function(){var ids=new Set(visCL().map(function(c){return String(c.id);}));if(right(CU).products.indexOf('mf')<0&&CU.role!=='Admin')return [];return SIPS.filter(function(s){return ids.has(String(s.clientId));});}; window.visINS=function(){var ids=new Set(visCL().map(function(c){return String(c.id);})),r=right(CU);if(CU.role!=='Admin'&&r.products.indexOf('health')<0&&r.products.indexOf('term')<0)return [];return INSURANCE.filter(function(i){return ids.has(String(i.clientId));});}; window.allVisibleProductRows=function(){var ids=allowedClientIds(),r=right(CU);return productRowsRaw().filter(function(x){return (ids===null||ids[String(x.clientId)])&&(CU.role==='Admin'||r.products.indexOf(productKind(x))>=0);});}; NAV.splice(1,0,{k:'engagement',i:'🤝',l:'Client Engagement'},{k:'tasks',i:'✅',l:'My Tasks'}); window.buildNav=function(){var html='';NAV.forEach(function(n){if(n.admin&&CU.role!=='Admin')return;if(!ocHasModule(n.k)&&CU.role!=='Admin')return;html+=''+n.i+''+n.l+'';});q('sbNav').innerHTML=html;}; var oldGo=window.goPage; window.goPage=function(k,from){if(CU&&CU.role!=='Admin'&&!ocHasModule(k)){alert('Admin ne is module ka access nahi diya hai.');k='dashboard';}oldGo(k,from);if(k==='engagement')ocRenderMeetings();if(k==='tasks')ocRenderTasks();if(k==='users')ocRenderAccess();}; function clientOptions(selected){return visCL().map(function(c){return '';}).join('');} function userOptions(selected){return staff().map(function(u){return '';}).join('');} function meetingVisible(m){return CU.role==='Admin'||m.owner===CU.u||m.createdBy===CU.u;} window.ocShowMeetingForm=function(edit,id){ocMeetingEdit=edit?id:null;var a=get(OC_MEET,[]),m=edit?a.filter(function(x){return String(x.id)===String(id);})[0]:null;m=m||{};q('ocMeetingForm').style.display='block';q('ocMeetingForm').innerHTML='
'+(edit?'Edit Meeting / Follow-up':'Add Client Meeting Note')+'
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'; }; window.ocSaveMeeting=function(){var cid=q('ocm_client').value;if(!cid||!q('ocm_date').value){alert('Client aur Meeting Date required hai.');return;}var c=clientById(cid),a=get(OC_MEET,[]),m={id:ocMeetingEdit||uid(),clientId:cid,client:c.name||'',date:q('ocm_date').value,mode:q('ocm_mode').value,purpose:q('ocm_purpose').value,owner:q('ocm_owner').value,status:q('ocm_status').value,advisorNotes:q('ocm_advisor').value.trim(),clientSaid:q('ocm_clientSaid').value.trim(),action:q('ocm_action').value.trim(),nextDate:q('ocm_next').value,createdBy:CU.u,updatedAt:new Date().toISOString()};if(ocMeetingEdit)a=a.map(function(x){return String(x.id)===String(ocMeetingEdit)?Object.assign({},x,m):x;});else a.push(m);put(OC_MEET,a);q('ocMeetingForm').style.display='none';ocMeetingEdit=null;ocRenderMeetings();try{renderDash();}catch(x){}alert('✅ Meeting note saved.');}; window.ocDeleteMeeting=function(id){if(!confirm('Meeting note delete karna hai?'))return;put(OC_MEET,get(OC_MEET,[]).filter(function(x){return String(x.id)!==String(id);}));ocRenderMeetings();}; window.ocRenderMeetings=function(){if(!q('ocMeetingTbl'))return;var a=get(OC_MEET,[]).filter(meetingVisible),s=(q('ocMeetingSearch')?q('ocMeetingSearch').value:'').toLowerCase(),st=q('ocMeetingStatus')?q('ocMeetingStatus').value:'';a=a.filter(function(m){return (!st||m.status===st)&&(!s||JSON.stringify(m).toLowerCase().indexOf(s)>=0);}).sort(function(x,y){return String(y.date).localeCompare(String(x.date));});var now=isoToday(),pending=a.filter(function(m){return m.status==='Follow-up Pending'||m.status==='Scheduled';}),over=pending.filter(function(m){return m.nextDate&&m.nextDate=0&&z<=7;});q('ocMeetingKpi').innerHTML=[['Total Meetings',a.length,'#1B4FD8'],['Open Follow-ups',pending.length,'#F59E0B'],['Next 7 Days',next7.length,'#16a34a'],['Overdue',over.length,'#EF4444']].map(function(x){return '
'+x[0]+'
'+x[1]+'
';}).join('');var h='Date / ClientPurpose / ModeDiscussionClient ResponseNext Follow-upOwner / StatusAction';if(!a.length)h+='No meeting notes available.';a.forEach(function(m){var u=USERS.filter(function(x){return x.u===m.owner;})[0]||{};h+=''+dmy(m.date)+'
'+e(m.client)+''+e(m.purpose)+'
'+e(m.mode)+''+e(m.advisorNotes||'—')+''+e(m.clientSaid||'—')+(m.action?'
Action: '+e(m.action)+'':'')+''+dmy(m.nextDate)+''+e(u.name||m.owner)+'
'+bd(m.status,m.status==='Completed'||m.status==='Closed'?'gr':m.status==='Scheduled'?'bl':'am')+'
'+(CU.role==='Admin'?'':'')+'
';});q('ocMeetingTbl').innerHTML=h+'';}; function taskVisible(t){return CU.role==='Admin'||t.assignedTo===CU.u||t.createdBy===CU.u;} window.ocShowTaskForm=function(edit,id){if(CU.role!=='Admin'&&!edit){alert('New task sirf Admin assign kar sakta hai.');return;}ocTaskEdit=edit?id:null;var a=get(OC_TASK,[]),t=edit?a.filter(function(x){return String(x.id)===String(id);})[0]:null;t=t||{};var isAdmin=CU.role==='Admin';q('ocTaskForm').style.display='block';q('ocTaskForm').innerHTML='
'+(edit?'Update Task':'Assign New Task')+'
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'; }; window.ocSaveTask=function(){var title=q('oct_title').value.trim(),status=q('oct_status').value,work=q('oct_work').value.trim();if(!title||!q('oct_due').value){alert('Task title aur due date required hai.');return;}if(CU.role!=='Admin'&&!work){alert('Aaj kya work kiya uska update likhna required hai.');return;}var a=get(OC_TASK,[]),old=ocTaskEdit?a.filter(function(x){return String(x.id)===String(ocTaskEdit);})[0]:{},cid=q('oct_client').value,c=cid?clientById(cid):{};var t={id:ocTaskEdit||uid(),title:title,assignedTo:q('oct_user').value,clientId:cid,client:c.name||'',dueDate:q('oct_due').value,priority:q('oct_priority').value,description:q('oct_desc').value.trim(),status:status,workDone:work,pendingReason:q('oct_pending').value.trim(),createdBy:old.createdBy||CU.u,createdAt:old.createdAt||new Date().toISOString(),updatedAt:new Date().toISOString()};if(ocTaskEdit)a=a.map(function(x){return String(x.id)===String(ocTaskEdit)?t:x;});else a.push(t);put(OC_TASK,a);q('ocTaskForm').style.display='none';ocTaskEdit=null;ocRenderTasks();try{renderDash();}catch(x){}if(status==='Completed'&&old.status!=='Completed')ocSendTaskEmail(t,'completed');alert('✅ Task update saved.');}; window.ocDeleteTask=function(id){if(!confirm('Task delete karna hai?'))return;put(OC_TASK,get(OC_TASK,[]).filter(function(x){return String(x.id)!==String(id);}));ocRenderTasks();}; window.ocRenderTasks=function(){if(!q('ocTaskTbl'))return;q('ocAddTaskBtn').style.display=CU.role==='Admin'?'inline-flex':'none';var a=get(OC_TASK,[]).filter(taskVisible),s=(q('ocTaskSearch')?q('ocTaskSearch').value:'').toLowerCase(),st=q('ocTaskStatus')?q('ocTaskStatus').value:'';a=a.filter(function(t){return (!st||t.status===st)&&(!s||JSON.stringify(t).toLowerCase().indexOf(s)>=0);}).sort(function(x,y){return String(x.dueDate).localeCompare(String(y.dueDate));});var now=isoToday(),done=a.filter(function(t){return t.status==='Completed';}),pending=a.filter(function(t){return t.status!=='Completed';}),over=pending.filter(function(t){return t.dueDate
'+x[0]+'
'+x[1]+'
';}).join('');var h='Task / ClientAssigned ToDue / PriorityAdmin InstructionsEmployee Daily UpdateStatusAction';if(!a.length)h+='No tasks available.';a.forEach(function(t){var u=USERS.filter(function(x){return x.u===t.assignedTo;})[0]||{};h+=''+e(t.title)+'
'+e(t.client||'General Task')+''+e(u.name||t.assignedTo)+''+dmy(t.dueDate)+'
'+bd(t.priority,t.priority==='High'?'rd':t.priority==='Medium'?'am':'gr')+''+e(t.description||'—')+''+e(t.workDone||'No update')+(t.pendingReason?'
Pending: '+e(t.pendingReason)+'':'')+''+bd(t.status,t.status==='Completed'?'gr':t.status==='In Progress'?'bl':t.status==='Pending'?'rd':'am')+'
'+(CU.role==='Admin'?'':'')+'
';});q('ocTaskTbl').innerHTML=h+'';}; function adminEmail(){return localStorage.getItem('ONECALL_ADMIN_EMAIL')||'prasadgaonkar007@gmail.com';} function mailHtml(subject,lines){return typeof buildOutlookHtml==='function'?buildOutlookHtml(subject,lines,'✅'):''+e(lines).replace(/\n/g,'
')+' ';} function sendMail(to,subject,text){var payload=JSON.stringify({to:to,subject:subject,html:mailHtml(subject,text),text:text}),urls=typeof valApis==='function'?valApis():[];function attempt(i){if(i>=urls.length){window.open('mailto:'+encodeURIComponent(to)+'?subject='+encodeURIComponent(subject)+'&body='+encodeURIComponent(text),'_blank');return Promise.reject(new Error('Email server unavailable; email compose opened.'));}return fetch(urls[i],{method:'POST',headers:{'Content-Type':'application/json'},body:payload}).then(function(r){return r.json().then(function(j){if(!r.ok||!j.ok)throw new Error(j.error||'Send failed');return j;});}).catch(function(){return attempt(i+1);});}return attempt(0);} window.ocSendTaskEmail=function(t,mode){var u=USERS.filter(function(x){return x.u===t.assignedTo;})[0]||{},sub='Task Completed: '+t.title,txt='Dear Sir,\n\n'+(u.name||t.assignedTo)+' has marked the following task as completed.\n\nTask: '+t.title+'\nClient: '+(t.client||'General')+'\nDue Date: '+dmy(t.dueDate)+'\nWork Completed: '+(t.workDone||'—')+'\nUpdated: '+new Date().toLocaleString('en-IN')+'\n\nRegards,\nONE CALL Task System';sendMail(adminEmail(),sub,txt).then(function(){alert('✅ Completion email sent to '+adminEmail());}).catch(function(){});}; window.ocSendDailyReport=function(){var day=isoToday(),a=get(OC_TASK,[]).filter(function(t){return taskVisible(t)&&String(t.updatedAt||'').slice(0,10)===day;}),who=CU.role==='Admin'?'All Employees':CU.name,sub='ONE CALL Daily Work Report | '+who+' | '+dmy(day),txt='Dear Sir,\n\nDaily work summary for '+who+' on '+dmy(day)+':\n\n'+(a.length?a.map(function(t,i){return (i+1)+'. '+t.title+'\nStatus: '+t.status+'\nWork Done: '+(t.workDone||'—')+'\nPending Reason: '+(t.pendingReason||'—');}).join('\n\n'):'No task update entered today.')+'\n\nRegards,\nONE CALL Task System';sendMail(adminEmail(),sub,txt).then(function(){alert('✅ Daily report sent to '+adminEmail());}).catch(function(){});}; window.ocSaveRights=function(user){var a=accessAll(),products=['mf','health','term','other'].filter(function(k){return q('ocr_'+user+'_'+k)&&q('ocr_'+user+'_'+k).checked;}),modules=['dashboard','clients','engagement','tasks','productwise','productentry','alerts','reports','documents','analytics','email','valuation','newfund','export'].filter(function(k){return q('ocm_'+user+'_'+k)&&q('ocm_'+user+'_'+k).checked;}),scope=q('ocs_'+user).value;a[user]={products:products,modules:modules,clientScope:scope};put(OC_ACCESS,a);alert('✅ Access rights saved for '+user+'. Next login se updated rights apply honge.');ocRenderAccess();}; window.ocRenderAccess=function(){if(CU.role!=='Admin'||!q('pg-users'))return;var box=q('ocAccessPanel');if(!box){box=document.createElement('div');box.id='ocAccessPanel';box.style.marginTop='14px';q('pg-users').appendChild(box);}var a=accessAll(),mods=[['dashboard','Dashboard'],['clients','Client Master'],['engagement','Client Engagement'],['tasks','Tasks'],['productwise','Product Wise'],['productentry','Product Entry'],['alerts','Alerts'],['reports','Reports'],['documents','Documents'],['analytics','Analytics'],['email','Email'],['valuation','Valuation'],['newfund','New Fund'],['export','Export']];var html='
📧 Notification Settings
Task completion and daily work report emails will go to this address.

🛡️ Employee Data Rights

Admin controls product data, client visibility and module access separately for each login.

'; staff().forEach(function(u){var r=a[u.u]||{products:[],modules:['dashboard','tasks'],clientScope:'none'};html+='
'+e(u.name)+' '+e(u.u)+'
'+[['mf','Mutual Fund'],['health','Health Insurance'],['term','Term Insurance'],['other','Other Products']].map(function(p){return '';}).join('')+'
'+mods.map(function(m){return '';}).join('')+'
';});box.innerHTML=html; var h='NameUsernameRoleDefault Data AccessStatus';USERS.forEach(function(u){var r=right(u),label=u.role==='Admin'?'Full Access':(r.products.length?r.products.map(function(x){return {mf:'Mutual Fund',health:'Health',term:'Term',other:'Other'}[x]||x;}).join(', '):'No Product Data');h+=''+e(u.name)+''+e(u.u)+''+bd(u.role,u.role==='Admin'?'am':'bl')+''+e(label)+''+bd('Active','gr')+'';});q('uTbl').innerHTML=h+''; }; var oldUsers=window.renderUsers;window.renderUsers=function(){try{oldUsers();}catch(x){}ocRenderAccess();}; var oldDash=window.renderDash;window.renderDash=function(){oldDash();try{var meetings=get(OC_MEET,[]).filter(meetingVisible),tasks=get(OC_TASK,[]).filter(taskVisible),now=isoToday(),follow=meetings.filter(function(m){return (m.status==='Follow-up Pending'||m.status==='Scheduled')&&m.nextDate&&m.nextDate>=now;}),pending=tasks.filter(function(t){return t.status!=='Completed';}),extra='
Upcoming Follow-ups
'+follow.length+'
Click for meeting list
Pending Tasks
'+pending.length+'
Click for assigned work
';q('kpiGrid').insertAdjacentHTML('beforeend',extra);}catch(x){}}; })(); /* ═════════════════════════════════════════════════════════════ V12: searchable/new client meetings + visible access control ═════════════════════════════════════════════════════════════ */ (function(){ function $v(id){return document.getElementById(id);} function esc12(v){return String(v==null?'':v).replace(/[&<>"']/g,function(c){return {'&':'&','<':'<','>':'>','"':'"',"'":'''}[c];});} function users12(){try{return JSON.parse(localStorage.getItem('ONECALL_USERS_V12')||'[]');}catch(e){return [];}} function saveUsers12(){localStorage.setItem('ONECALL_USERS_V12',JSON.stringify(USERS.map(function(u){return {u:u.u,p:u.p,role:u.role,name:u.name,rm:u.rm||null};})));} users12().forEach(function(saved){var live=USERS.filter(function(u){return u.u===saved.u;})[0];if(live)Object.assign(live,saved);else USERS.push(saved);}); var sar=USERS.filter(function(u){return u.u==='sarika.kedari';})[0];if(sar){sar.role='Employee';sar.rm=null;} var pri=USERS.filter(function(u){return u.u==='priya.gaonkar';})[0];if(!pri){pri={u:'priya.gaonkar',p:'rm123',role:'Employee',name:'Priya Gaonkar',rm:null};USERS.push(pri);}else{pri.role='Employee';pri.rm=null;} if(!NAV.some(function(n){return n.k==='access';})) NAV.splice(3,0,{k:'access',i:'🛡️',l:'Access Control',admin:true}); var go12=window.goPage; window.goPage=function(k,from){go12(k,from);if(k==='access')ocRenderAccessV12();}; var accessPage=document.createElement('div');accessPage.className='pg';accessPage.id='pg-access'; accessPage.innerHTML='

🛡️ Access Control & Employee Logins

Separate login, password and product-wise data rights

'; var main=$v('MN');if(main)main.appendChild(accessPage); function clientToken(c){return (c.name||'')+' | '+(c.pan||'No PAN')+' | '+(c.mobile||'No Mobile');} function findClient12(s){s=String(s||'').trim().toLowerCase();if(!s)return null;return visCL().filter(function(c){return clientToken(c).toLowerCase()===s||String(c.name||'').toLowerCase()===s||String(c.pan||'').toLowerCase()===s||String(c.mobile||'').toLowerCase()===s;})[0]||null;} window.ocMeetingClientMode=function(){var mode=$v('ocm_clientMode').value,isNew=mode==='new';$v('ocm_existingWrap').style.display=isNew?'none':'block';$v('ocm_newWrap').style.display=isNew?'block':'none';}; window.ocShowMeetingForm=function(edit,id){ window.ocMeetingEdit=edit?id:null; var all=JSON.parse(localStorage.getItem('ONECALL_MEETINGS_V11')||'[]'),m=edit?all.filter(function(x){return String(x.id)===String(id);})[0]:null;m=m||{}; var isNew=!!m.isNewClient,clients=visCL(),savedClient=(!isNew&&m.clientId)?clientById(m.clientId):null,list=clients.map(function(c){return '';}).join(''); var owners=USERS.filter(function(u){return u.role!=='Admin';}).map(function(u){return '';}).join(''); $v('ocMeetingForm').style.display='block'; $v('ocMeetingForm').innerHTML='
'+(edit?'Edit Meeting / Follow-up':'Add Client Meeting Note')+'
'+ '
'+ '
'+list+'
Name/PAN/mobile type karein aur matching client select karein.
'+ ''+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'; window.$v=$v;ocMeetingClientMode(); }; window.ocSaveMeetingV12=function(){ var mode=$v('ocm_clientMode').value,c=null,name='',cid='',pan='',mobile='',email=''; if(mode==='existing'){c=findClient12($v('ocm_clientSearch').value);if(!c){alert('Existing client list se valid client select karein. Naya client hai to Client Type mein New Client choose karein.');return;}name=c.name;cid=c.id;pan=c.pan||'';mobile=c.mobile||'';email=c.email||'';} else{name=$v('ocm_newName').value.trim();mobile=$v('ocm_newMobile').value.trim();email=$v('ocm_newEmail').value.trim();if(!name){alert('New Client Name required hai.');return;}} if(!$v('ocm_date').value){alert('Meeting Date required hai.');return;} var key='ONECALL_MEETINGS_V11',a=JSON.parse(localStorage.getItem(key)||'[]'),editId=window.ocMeetingEdit; var old=editId?a.filter(function(x){return String(x.id)===String(editId);})[0]||{}:{}; var m={id:editId||Date.now()+Math.floor(Math.random()*10000),clientId:cid,client:name,clientPan:pan,clientMobile:mobile,clientEmail:email,isNewClient:mode==='new',date:$v('ocm_date').value,mode:$v('ocm_mode').value,purpose:$v('ocm_purpose').value,owner:$v('ocm_owner').value,status:$v('ocm_status').value,advisorNotes:$v('ocm_advisor').value.trim(),clientSaid:$v('ocm_clientSaid').value.trim(),action:$v('ocm_action').value.trim(),nextDate:$v('ocm_next').value,createdBy:old.createdBy||CU.u,updatedAt:new Date().toISOString()}; if(editId)a=a.map(function(x){return String(x.id)===String(editId)?m:x;});else a.push(m);localStorage.setItem(key,JSON.stringify(a));$v('ocMeetingForm').style.display='none';window.ocMeetingEdit=null;ocRenderMeetings();renderDash();alert('✅ '+(mode==='new'?'New client':'Existing client')+' meeting note saved.'); }; window.ocSaveLoginV12=function(username){var u=USERS.filter(function(x){return x.u===username;})[0],p=$v('ocp_'+username).value.trim();if(!u||!p){alert('Password blank nahi ho sakta.');return;}u.p=p;saveUsers12();alert('✅ '+u.name+' ka login password saved.');ocRenderAccessV12();}; window.ocRenderAccessV12=function(){if(!CU||CU.role!=='Admin')return;if(typeof oldAccess==='function')oldAccess();var host=$v('ocAccessV12'),a=JSON.parse(localStorage.getItem('ONECALL_ACCESS_V11')||'{}');var targets=['sarika.kedari','priya.gaonkar'];var html='
';targets.forEach(function(username){var u=USERS.filter(function(x){return x.u===username;})[0],r=a[username]||((username==='sarika.kedari')?{products:['mf'],clientScope:'product'}:{products:['health','term'],clientScope:'product'}),label=(r.products||[]).map(function(x){return {mf:'Mutual Fund',health:'Health Insurance',term:'Term Insurance',other:'Other Products'}[x]||x;}).join(', ');html+='
👤 '+esc12(u.name)+'
Username'+esc12(u.u)+'Password
RoleEmployeeData Access'+esc12(label||'No access')+'Client ScopeOnly clients having allowed product
';});html+='
Login Separation Active
Sarika aur Priya apne username/password se Employee login karengi. Dono ko doosre employee ka restricted product data nahi dikhega. Admin ko full data dikhega.
';host.innerHTML=html; var oldPanel=$v('ocAccessPanel');if(oldPanel){oldPanel.style.display='block';$v('ocRightsEmbedded').appendChild(oldPanel);} }; var oldAccess=window.ocRenderAccess;window.ocRenderAccess=function(){oldAccess();if($v('pg-access')&&$v('pg-access').classList.contains('on'))ocRenderAccessV12();}; var login12=window.doLogin;window.doLogin=function(){login12();if(CU&&CU.role==='Admin'){setTimeout(function(){try{buildNav();}catch(e){}},0);}}; })();