Form 31 Generator - Section 9(2) Notice Automator
Back to Dashboard
Andhra Pradesh Land Resurvey Statutory Notice Generator Tool. Generate Form-31 Notices
under Section 9(2) of AP Survey and Boundaries Act 1923. Features: LPM Number mapping,
farmer-wise notice generation, and PDF/Word download. Free tool for Surveyors in AP
Andhra Pradesh Land
Resurvey Section 9(2) Notice
Generator
(Form-31) Upload Excel File
Required Excel Columns Please ensure your file
includes headers similar to:
చల్తా నెం. /
ల్యాండ్ పార్సెల్ నెం.
సర్వే నెంబరు
ఖాతా నెంబరు
భూ యజమాని పేరు
తండ్రి పేరు
ROR
విస్తీర్ణము
(హె./ఎ.)
రీసర్వే
విస్తీర్ణము (హె./ఎ.)
Drag & drop your Excel file here
or click to browse (.xlsx, .xls)
Form 31 Notice GeneratorGenerate Statutory Notices under Section 9(2) for Land Resurvey
Notice Metadata
Auto-fill Last Entries
Generate Notices
Mode
-
Records
-
Village
-
Count
-
Combine all notices in one file (Individual Notices)
Group by Base Survey No. (Smart Grouping)
Merge All into Single Notice (General Public Notice)
Filter Records
(Optional)
- Leave empty to
process all
Download Format:
DOCX (Word Document) PDF (Print to Save)
Generate All Notices
Notices generated successfully!
Download All Notices (ZIP)
`;// Open print window
const printWindow = window.open('', '_blank', 'width=800,height=600');
printWindow.document.write(printHtml);
printWindow.document.close();// Wait for fonts to load, then print
printWindow.onload = function () {
setTimeout(() => {
printWindow.print();
}, 1000);
};downloadBtn.disabled = false;
downloadBtn.innerHTML = `
Download All Notices
`;
return; // Early return for PDF} else {
// DOCX Generation
if (combineNotices) {
// Combined DOCX - regenerate all notices into one document with sections
const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, WidthType, AlignmentType, BorderStyle, PageBreak, Footer, PageNumber } = docxLib;// Collect all section children for combined document
const allSections = [];for (let i = 0; i < this.generatedDocuments.length; i++) {
const { key, rows, metadata } = this.generatedDocuments[i];
// Re-create the section for this notice
const sectionChildren = await this.createNoticeSectionChildren(key, rows, metadata, docxLib);allSections.push({
properties: {
page: {
margin: {
top: 1134, // 2cm
bottom: 1134,
left: 1134,
right: 1134
},
borders: {
pageBorderTop: { style: BorderStyle.SINGLE, size: 8, color: '000000', space: 24 },
pageBorderBottom: { style: BorderStyle.SINGLE, size: 8, color: '000000', space: 24 },
pageBorderLeft: { style: BorderStyle.SINGLE, size: 8, color: '000000', space: 24 },
pageBorderRight: { style: BorderStyle.SINGLE, size: 8, color: '000000', space: 24 }
}
}
},
footers: isMergeMode ? {
default: new Footer({
children: [
new Paragraph({
alignment: AlignmentType.RIGHT,
children: [
new TextRun({ children: ["Page ", PageNumber.CURRENT, " of ", PageNumber.TOTAL_PAGES] }),
],
}),
],
}),
} : undefined,
children: sectionChildren
});
}// Create combined document
const combinedDoc = new Document({ sections: allSections });
const blob = await Packer.toBlob(combinedDoc);
saveAs(blob, `Form31_Notices_Combined_${village}.docx`);} else {
const zip = new JSZip();
for (const { key, doc, ownerName } of this.generatedDocuments) {
const blob = await docxLib.Packer.toBlob(doc);
const sanitizedOwnerName = String(ownerName || 'Unknown').replace(/[<>:"/\\|?*\n\r]/g, '_').trim();
const sanitizedKey = String(key).replace(/[<>:"/\\|?*\n\r]/g, '_').trim();
let fileName;
if (this.generationMode === 'khata') {
fileName = `${sanitizedKey}_Khata_${sanitizedOwnerName}.docx`;
} else if (this.generationMode === 'survey') {
fileName = `${sanitizedKey}_Survey_${sanitizedOwnerName}.docx`;
} else if (this.generationMode === 'lpm') {
fileName = `${sanitizedKey}_LPM_${sanitizedOwnerName}.docx`;
} else {
fileName = `Notice_${sanitizedKey}.docx`;
}
zip.file(fileName, blob);
}
const zipBlob = await zip.generateAsync({ type: 'blob' });
saveAs(zipBlob, `Form31_Notices_${village}.zip`);
}
}} catch (error) {
console.error('Download error:', error);
alert('Error creating download. Please try again.');
}downloadBtn.disabled = false;let btnLabel = 'Download All Notices (ZIP)';
if (combineNotices) {
btnLabel = 'Download Combined DOCX';
}downloadBtn.innerHTML = `
${btnLabel}
`;
}// ===== Start Over =====
startOver() {
const shouldReset = confirm('Are you sure you want to start a new generation? All data will be cleared.');if (shouldReset) {
this.resetApplication();
}
}resetApplication() {
try {
this.excelData = null;
this.headers = [];
this.generationMode = 'lpm'; // Form 31 uses LPM mode only
this.columnMappings = {};
this.generatedDocuments = [];// Reset UI
const uploadZone = document.getElementById('uploadZone');
const fileInfo = document.getElementById('fileInfo');
const excelFile = document.getElementById('excelFile');if (uploadZone) uploadZone.classList.remove('hidden');
if (fileInfo) fileInfo.classList.add('hidden');
if (excelFile) excelFile.value = '';document.getElementById('nextStep1').disabled = true;
document.getElementById('nextStep2').disabled = false; // LPM mode auto-selected
document.getElementById('nextStep3').disabled = true;const metadataForm = document.getElementById('metadataForm');
if (metadataForm) metadataForm.reset();document.querySelectorAll('input[name="generationMode"]').forEach(r => r.checked = false);const progressContainer = document.getElementById('progressContainer');
const downloadSection = document.getElementById('downloadSection');
const progressFill = document.getElementById('progressFill');if (progressContainer) progressContainer.classList.add('hidden');
if (downloadSection) downloadSection.classList.add('hidden');
if (progressFill) progressFill.style.width = '0%';this.goToStep(1);console.log('Application reset successfully');
} catch (error) {
console.error('Error resetting application:', error);
// Force reload as fallback
window.location.reload();
}
}// ===== Helper: Setup Help System (Floating Button) =====
setupHelpSystemFloating() {
// Avoid duplicate creation
if (document.getElementById('helpBtn')) return;// 1. Inject Styles
const style = document.createElement('style');
style.innerHTML = `
.help-float-container {
position: fixed !important;
bottom: 150px !important;
left: 30px !important;
z-index: 2147483647 !important;
display: flex !important;
flex-direction: column;
align-items: center;
gap: 8px;
}
.help-float-label {
background: #1e40af;
color: white;
padding: 6px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: 600;
white-space: nowrap;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
animation: labelPulse 2s infinite ease-in-out;
}
@keyframes labelPulse {
0 %, 100 % { opacity: 1; }
50% {opacity: 0.7; }
}
.help-float-btn {
width: 60px;
height: 60px;
border-radius: 50%;
background: linear-gradient(135deg, #2563eb 0%, #1e40af 100%);
color: white !important;
border: none;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
cursor: pointer;
display: flex !important;
align-items: center;
justify-content: center;
font-size: 24px;
transition: transform 0.3s, box-shadow 0.3s;
animation: floatPulse 3s infinite ease-in-out;
}
@keyframes floatPulse {
0 % { transform: translateY(0); box- shadow: 0 4px 15px rgba(0,0,0,0.3); }
50% {transform: translateY(-5px); box-shadow: 0 8px 25px rgba(0,0,0,0.4); }
100% {transform: translateY(0); box-shadow: 0 4px 15px rgba(0,0,0,0.3); }
}
.help-float-btn:hover {
transform: scale(1.1) rotate(10deg);
animation: none;
}
.help-modal {
position: fixed !important;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0, 0, 0, 0.7);
z-index: 2147483647 !important;
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(4px);
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease;
}
.help-modal.active {opacity: 1; pointer-events: auto; }
.help-modal-content {
background: white;
width: 90%; max-width: 600px;
border-radius: 16px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
overflow: hidden;
transform: translateY(20px);
transition: transform 0.3s ease;
max-height: 90vh;
display: flex; flex-direction: column;
font-family: inherit;
}
.help-modal.active .help-modal-content {transform: translateY(0); }
.help-header {
background: #f8fafc; padding: 20px 25px;
border-bottom: 1px solid #e2e8f0;
display: flex; justify-content: space-between; align-items: center;
}
.help-header h3 {margin: 0; color: #0f172a; font-size: 1.25rem; display: flex; align-items: center; gap: 10px; }
.close-help-btn {background: none; border: none; font-size: 24px; cursor: pointer; color: #64748b; }
.close-help-btn:hover {color: #ef4444; }
.help-body {padding: 25px; overflow-y: auto; text-align: left; }
.help-step {display: flex; gap: 15px; margin-bottom: 20px; align-items: flex-start; }
.step-badge {
background: #e2e8f0; color: #475569; width: 28px; height: 28px;
border-radius: 50%; display: flex; align-items: center; justify-content: center;
font-weight: bold; flex-shrink: 0; margin-top: 2px;
}
.help-footer {padding: 15px 25px; background: #f8fafc; text-align: right; border-top: 1px solid #e2e8f0; }
`;
document.head.appendChild(style);// 2. Inject Button Container with Label
const container = document.createElement('div');
container.id = 'helpBtnContainer';
container.className = 'help-float-container';const label = document.createElement('span');
label.className = 'help-float-label';
label.textContent = 'How to Use';
container.appendChild(label);const btn = document.createElement('button');
btn.id = 'helpBtn';
btn.className = 'help-float-btn';
btn.innerHTML = '
';
btn.title = 'Help Guide';
btn.onclick = window.toggleHelpModal;
container.appendChild(btn);document.body.appendChild(container);// 3. Inject Modal
const modal = document.createElement('div');
modal.id = 'helpModal';
modal.className = 'help-modal';
modal.innerHTML = `
1 Upload Excel File Upload your Resurvey data (.xlsx). Ensure headers include: LPM No., Survey No., Khata No., Owner Name, etc.
2 Select Mode • LPM Mode: One notice per Land Parcel (Default). • Khata Mode: Group multiple LPMs into one notice per Khata.
3 Map Columns Map required fields including Khata Number (if using Khata Mode). NEW: Enable 'Auto Calculate' checkbox to auto-generate ROR Hectare values (హె.ఏర్లు.చ.మీ.) from Acres with smart rounding.
4 Enter Notice Details Fill District, Mandal, Village, and Notice Date. Use 'Auto-fill' to load saved details.
5 Generate & Download • Combine All: Download a single DOCX file with all notices. • ZIP: Download individual files. • KHATA No. is added to Farmer Name automatically.
`;
document.body.appendChild(modal);// 4. Window global for toggle
window.toggleHelpModal = () => {
const m = document.getElementById('helpModal');
if (m) m.classList.toggle('active');
};
}
}// Initialize the application
document.addEventListener('DOMContentLoaded', () => {
window.noticeGenerator = new NoticeGenerator();
});