${field('deducteeName','Seller / landlord full name','text',{required:true})}${field('deducteePan','Seller / landlord PAN','text',{required:true,placeholder:'ABCDE1234F'})}${field('deducteeEmail','Seller / landlord email','email')}${field('deducteePhone','Seller / landlord contact','tel')}${field('deducteeSharePercent','Seller / landlord share (%)','number',{required:true})}${field('propertyType','Property type','text',{options:state.schedule==='A'?[['building','Building'],['land','Land'],['land-building','Land and building']]:[['building','Building or part of building'],['land','Land other than agricultural land']]})}${field('propertyAddress','Property address','text',{wide:true,required:true})}
${field('monthlyRent','Monthly rent (₹)','number',{required:true})}${field('tenancyMonths','Tenancy months in tax year','number',{required:true})}${field('totalRent','Total rent during tax year (₹)','number',{required:true})}${field('lastMonthRent','Rent in last month (₹)','number',{required:true})}${field('tenancyEndReason','Reason for deduction','text',{options:[['tax-year-end','End of tax year'],['tenancy-end','End of tenancy']]})}${field('paymentDate','Credit / payment date','date',{required:true})}
` : `
Schedule B · Immovable property transfer
${field('sellerResidency','Seller residency','text',{options:[['resident','Resident'],['nonresident','Non-resident']]})}${field('agreementDate','Agreement date','date')}${field('registrationDate','Registration date, if available','date')}${field('saleConsideration','Total sale consideration (₹)','number',{required:true})}${field('stampValue','Total stamp duty value (₹)','number',{required:true})}${field('paymentMode','Payment mode','text',{options:[['lumpsum','Lump sum'],['instalments','Instalments']]})}${field('instalmentStage','Instalment stage','text',{options:[['first','First'],['subsequent','Subsequent'],['last','Last']]})}${field('previousAcknowledgement','Previous acknowledgement, if applicable')}${field('previousPayments','Earlier instalments paid (₹)','number')}${field('currentPayment','Current payment (₹)','number',{required:true})}${field('paymentDate','Credit / payment date','date',{required:true})}
`;
function renderForm(preserve={}) {
form.innerHTML=`
TDS & Form 141 workspace
Prepare, review and export your transaction
`;
form.querySelector('.cg-release-close').onclick=()=>form.close();
form.querySelectorAll('[data-schedule]').forEach(button=>button.onclick=()=>{ const values=valuesOf(); state.schedule=button.dataset.schedule; renderForm(values); });
const saved={...preserve}; if (!('rate' in saved)) saved.rate=state.schedule==='A'?2:1; if (!('deductorSharePercent' in saved)) saved.deductorSharePercent=100; if (!('deducteeSharePercent' in saved)) saved.deducteeSharePercent=100;
Object.entries(saved).forEach(([key,value])=>{const input=form.querySelector(`[name="${key}"]`); if(input && value!=null) input.value=String(value)});
form.querySelectorAll('input,select,textarea').forEach(input=>input.addEventListener('input',updateForm));
form.querySelectorAll('[data-export]').forEach(button=>button.onclick=()=>exportForm(button.dataset.export));
form.querySelector('[data-save]').onclick=()=>{const v=valuesOf();localStorage.setItem('capgain-form141-draft-v1',JSON.stringify(v)); message('Worksheet saved in this browser.','good');};
updateForm();
}
function valuesOf(){const v={schedule:state.schedule};form.querySelectorAll('#cg-release-form [name]').forEach(input=>v[input.name]=input.value.trim());v.deductorPan=(v.deductorPan||'').toUpperCase();v.deducteePan=(v.deducteePan||'').toUpperCase();return v}
function message(text,kind='error'){const node=$('#cg-release-errors');if(node)node.innerHTML=text?`
${e(text)}
`:''}
function updateForm(){const v=valuesOf(),calc=estimateForm141(v),errors=validateForm141(v);$('#cg-release-summary').innerHTML=`Estimated deduction${inr(calc.tax)}
Review deductions, exemptions, lower certificates and party shares before filing.`;form.querySelectorAll('[data-export]').forEach(button=>button.disabled=errors.length>0);message(errors.length?errors.slice(0,3).join(' '):'')}
function download(blob,name){const url=URL.createObjectURL(blob),link=document.createElement('a');link.href=url;link.download=name;document.body.append(link);link.click();link.remove();setTimeout(()=>URL.revokeObjectURL(url),30000)}
function pdfEscape(text){return String(text).normalize('NFKD').replace(/[^\x20-\x7e]/g,'?').replace(/[\\()]/g,'\\$&')}
function pdfDraft(data){
const rows=[['CAPGAIN | FORM 141 PREPARATION DRAFT',20],['Not an Income Tax portal submission or challan',11],['Schedule '+data.schedule+(data.schedule==='A'?' - Rent paid by Individual/HUF':' - Immovable property transfer'),13],['Generated '+data.generatedAt.slice(0,10),10],['',10],['PART A - DEDUCTOR',12]];
const add=(label,value)=>rows.push([`${label}: ${value||'-'}`,10]);
for(const [k,v] of Object.entries(data.partA))add(k.replace(/([A-Z])/g,' $1'),v);
rows.push(['',10],['PART B - TRANSACTION',12]);
const selected=data.schedule==='A'?['deducteeName','deducteePan','deducteeEmail','deducteePhone','deducteeSharePercent','propertyAddress','propertyType','monthlyRent','tenancyMonths','totalRent','lastMonthRent','tenancyEndReason','paymentDate','deductionDate']:['deducteeName','deducteePan','deducteeEmail','deducteePhone','deducteeSharePercent','propertyAddress','propertyType','agreementDate','registrationDate','saleConsideration','stampValue','paymentMode','instalmentStage','previousAcknowledgement','previousPayments','currentPayment','paymentDate','deductionDate'];
selected.forEach(k=>add(k.replace(/([A-Z])/g,' $1'),data.partB[k]));
add('Certificate number',data.partB.certificateNumber); rows.push(['',10],['CALCULATION',12]);add('Amount liable to deduction','Rs '+data.calculation.base.toLocaleString('en-IN'));add('Rate',data.calculation.rate+'%');add('Estimated TDS','Rs '+data.calculation.tax.toLocaleString('en-IN'));add('Indicative payment deadline',data.calculation.due);
rows.push(['',10],['Verify every field against source records before portal filing.',10],['Official source: incometax.gov.in - Form 141 FAQs',9],['This CAPGAIN PDF is a readable draft only.',9]);
const lines=[];for(const [text,size] of rows){const limit=size>12?65:89;const words=String(text).split(/\s+/);let line='';for(const word of words){if((line+' '+word).length>limit){lines.push([line,size]);line=word}else line+=(line?' ':'')+word}lines.push([line,size])}
const pages=[];while(lines.length)pages.push(lines.splice(0,45));const objects=[];const addObj=s=>{objects.push(s);return objects.length};const root=addObj('');const pagesRef=addObj('');const font=addObj('<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>');const pageIds=[];
pages.forEach((page,idx)=>{let content='BT\n';let y=790;page.forEach(([line,size])=>{content+=`/F1 ${size} Tf 1 0 0 1 45 ${y} Tm (${pdfEscape(line)}) Tj\n`;y-=size+7});content+=`/F1 9 Tf 1 0 0 1 45 27 Tm (Page ${idx+1} of ${pages.length}) Tj\nET`;const stream=addObj(`<< /Length ${new TextEncoder().encode(content).length} >>\nstream\n${content}\nendstream`);pageIds.push(addObj(`<< /Type /Page /Parent ${pagesRef} 0 R /MediaBox [0 0 595 842] /Resources << /Font << /F1 ${font} 0 R >> >> /Contents ${stream} 0 R >>`))});objects[root-1]=`<< /Type /Catalog /Pages ${pagesRef} 0 R >>`;objects[pagesRef-1]=`<< /Type /Pages /Kids [${pageIds.map(n=>n+' 0 R').join(' ')}] /Count ${pageIds.length} >>`;
let pdf='%PDF-1.4\n',offsets=[0];objects.forEach((obj,i)=>{offsets.push(new TextEncoder().encode(pdf).length);pdf+=`${i+1} 0 obj\n${obj}\nendobj\n`});const xref=new TextEncoder().encode(pdf).length;pdf+=`xref\n0 ${objects.length+1}\n0000000000 65535 f \n`;offsets.slice(1).forEach(o=>pdf+=`${String(o).padStart(10,'0')} 00000 n \n`);pdf+=`trailer\n<< /Size ${objects.length+1} /Root ${root} 0 R >>\nstartxref\n${xref}\n%%EOF`;return new Blob([pdf],{type:'application/pdf'})
}
function exportForm(kind){const v=valuesOf(),errors=validateForm141(v);if(errors.length){message(errors.join(' '));return}const data=worksheet(v),base=`CAPGAIN-Form141-Schedule-${v.schedule}-${v.deductionDate}`;if(kind==='pdf')download(pdfDraft(data),base+'.pdf');if(kind==='json')download(new Blob([JSON.stringify(data,null,2)],{type:'application/json'}),base+'.json');if(kind==='xml')download(new Blob([toXML(data)],{type:'application/xml'}),base+'.xml')}
function openForm(){const saved=JSON.parse(localStorage.getItem('capgain-form141-draft-v1')||'null')||{};state.schedule=saved.schedule||'B';renderForm(saved);form.showModal()}
function renderDocs(){docs.innerHTML=`
Document intelligence
Read a deed or property record, then review transaction details
Files are processed in your browser for this preview. Review every extracted value against the original document.
English OCR runs in this browser using bundled language data. This desk never files a tax form or assumes a candidate is correct.
`;docs.querySelector('.cg-release-close').onclick=()=>docs.close();$('#cg-doc-file').onchange=event=>readDoc(event.target.files[0]);$('#cg-doc-form').onclick=()=>{const picked={};docs.querySelectorAll('[data-candidate]').forEach(node=>{if(node.checked){const c=state.candidates[Number(node.dataset.candidate)];picked[c.field]=c.value}});docs.close();const saved=JSON.parse(localStorage.getItem('capgain-form141-draft-v1')||'null')||{};state.schedule='B';renderForm({...saved,...picked});form.showModal()};$('#cg-doc-assistant').onclick=()=>{const summary=state.candidates.map(c=>`${c.label}: ${c.value}`).join('; ');docs.close();if(window.CG?.assistant?.ask){window.CG.assistant.open?.();window.CG.assistant.ask(`Help me review this property transaction. Extracted details to verify: ${summary}. Explain capital gains and TDS questions.`)}else alert('CG Assistant is available from Home. Review these document details first: '+summary)}}
async function loadOCR(){if(!window.Tesseract){await new Promise((resolve,reject)=>{const script=document.createElement('script');script.src='vendor/tesseract.min.js';script.onload=resolve;script.onerror=reject;document.head.append(script)})}return window.Tesseract}
async function ocrImage(image){const T=await loadOCR();const result=await T.recognize(image,'eng',{workerPath:'vendor/worker.min.js',corePath:'vendor/tesseract-core-simd-lstm.wasm.js',langPath:'vendor',gzip:false});return result.data.text||''}
async function readDoc(file){if(!file)return;const status=$('#cg-doc-status');status.textContent='Reading '+file.name+'…';state.scannedFile=file.name;try{if(file.size>20*1024*1024)throw Error('File exceeds 20 MB.');let text='';if(file.type==='application/pdf'||/\.pdf$/i.test(file.name)){const pdfjs=await import('./vendor/capgain-pdf.min.mjs');pdfjs.GlobalWorkerOptions.workerSrc='./vendor/pdf.worker.min.mjs';const buffer=await file.arrayBuffer();const pdf=await pdfjs.getDocument({data:buffer}).promise;const count=Math.min(pdf.numPages,20);for(let n=1;n<=count;n++){status.textContent=`Reading PDF page ${n} of ${count}…`;const page=await pdf.getPage(n);const layer=await page.getTextContent();let pageText=layer.items.map(item=>item.str).join(' ');if(pageText.trim().length<30){const viewport=page.getViewport({scale:1.8});const canvas=document.createElement('canvas');canvas.width=viewport.width;canvas.height=viewport.height;await page.render({canvasContext:canvas.getContext('2d'),viewport}).promise;pageText=await ocrImage(canvas)}text+=`\n[Page ${n}] ${pageText}`}}else if(file.type.startsWith('image/')){text=await ocrImage(file)}else throw Error('Choose a PDF, PNG, JPEG or WebP file.');state.extractedText=text;state.candidates=extractCandidates(text);status.textContent=`Read ${text.length.toLocaleString()} characters from ${file.name}. ${state.candidates.length} possible fields need your review.`;$('#cg-doc-candidates').innerHTML=state.candidates.length?state.candidates.map((c,i)=>``).join(''):'No transaction fields found. Try a clearer scan or enter the details manually.';$('#cg-doc-form').disabled=!state.candidates.length;$('#cg-doc-assistant').disabled=!state.candidates.length}catch(error){status.textContent='Document reading could not finish: '+error.message}}
function openDocs(){renderDocs();docs.showModal()}
function install(){
const head=$('#topbar');if(head&&!$('#cg-release-nav')){const button=document.createElement('button');button.id='cg-release-nav';button.className='cg-release-nav';button.textContent='TDS & Form 141';button.onclick=openForm;head.insertBefore(button,$('#btn-search'))}
const createCard=(parent,id,img,title,sub,action)=>{if(!parent||$('#'+id))return;const el=document.createElement('div');el.id=id;el.className='cg-release-shortcut';el.innerHTML=`
${title}
${sub}
`;el.querySelector('button').onclick=action;parent.prepend(el)};
createCard($('#pg-home'),'cg-release-assistant','Calculator','CG Assistant','Ask about property tax, a transaction or the document you just reviewed.',()=>{window.CG?.assistant?.open?.()});
createCard($('#pg-home'),'cg-release-home','Home','Real estate transactions, clearly planned','Explore tax, TDS, documents and personal guidance in one place.',openForm);
createCard($('#pg-calculators'),'cg-release-calcs','TDS','TDS & Form 141','Schedule A rent and Schedule B immovable property, with a readable PDF draft and separate data exports.',openForm);
createCard($('#pg-my'),'cg-release-docs','Documents','Document intelligence','Read a sale deed or property record, review extracted details and continue to tax planning.',openDocs);
const news=$('#pg-news');if(news){news.querySelectorAll('h1,h2').forEach(h=>{if(/^news$|^live news$|^latest news$/i.test(h.textContent.trim()))h.textContent='Real Estate Transactions Tax News'})}
document.title='CAPGAIN — Real Estate Transactions Tax';
const meta=document.querySelector('meta[name="description"]');if(meta)meta.content='CAPGAIN real estate transaction tax calculators, Form 141 preparation, documents and advisory for India.';
}
document.addEventListener('DOMContentLoaded',()=>{install();setTimeout(install,600);const observer=new MutationObserver(()=>{if(!$('#cg-release-calcs')||!$('#cg-release-home'))install()});observer.observe($('#pages')||document.body,{childList:true,subtree:true})});
window.CapGainRelease={openForm,openDocs,taxScope};