feat: add professor import support, user account creation, and IBAN/card fields
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
// /scripts/convert-professors.js
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
const ODS_FILE = path.resolve(__dirname, '../../raw-data/Untitled spreadsheet.ods');
|
||||
const OUTPUT_FILE = path.resolve(__dirname, '../../raw-data/professors-import.json');
|
||||
|
||||
const pythonExtractScript = `
|
||||
import zipfile, xml.etree.ElementTree as ET, json, sys
|
||||
|
||||
ods_path = sys.argv[1]
|
||||
with zipfile.ZipFile(ods_path) as z:
|
||||
content = z.read('content.xml')
|
||||
tree = ET.fromstring(content)
|
||||
for table in tree.iter('{urn:oasis:names:tc:opendocument:xmlns:table:1.0}table'):
|
||||
rows = []
|
||||
for row in table.iter('{urn:oasis:names:tc:opendocument:xmlns:table:1.0}table-row'):
|
||||
row_vals = []
|
||||
for cell in row.iter('{urn:oasis:names:tc:opendocument:xmlns:table:1.0}table-cell'):
|
||||
texts = [t.text for t in cell.iter('{urn:oasis:names:tc:opendocument:xmlns:text:1.0}p') if t.text]
|
||||
repeat = int(cell.attrib.get('{urn:oasis:names:tc:opendocument:xmlns:table:1.0}number-columns-repeated', 1))
|
||||
val = ' '.join(texts).strip() if texts else ''
|
||||
if repeat > 1 and not val:
|
||||
pass
|
||||
else:
|
||||
for _ in range(min(repeat, 20)):
|
||||
row_vals.append(val)
|
||||
if any(row_vals):
|
||||
rows.append(row_vals)
|
||||
print(json.dumps(rows, ensure_ascii=False))
|
||||
break
|
||||
`;
|
||||
|
||||
const extractOdsRows = (filePath) => {
|
||||
const output = execSync(`python3 -c "${pythonExtractScript.replace(/"/g, '\\"')}" "${filePath}"`, {
|
||||
encoding: 'utf-8',
|
||||
maxBuffer: 10 * 1024 * 1024
|
||||
});
|
||||
return JSON.parse(output);
|
||||
};
|
||||
|
||||
const toEnglishDigits = (str = '') =>
|
||||
String(str)
|
||||
.replace(/[۰-۹]/g, (d) => '0123456789'['۰۱۲۳۴۵۶۷۸۹'.indexOf(d)])
|
||||
.replace(/[٠-٩]/g, (d) => '0123456789'['٠١٢٣٤٥٦٧٨٩'.indexOf(d)]);
|
||||
|
||||
const cleanPhone = (raw) => {
|
||||
if (!raw) return '';
|
||||
let digits = toEnglishDigits(raw).replace(/\D/g, '');
|
||||
if (digits.startsWith('98') && digits.length >= 12) digits = `0${digits.slice(2)}`;
|
||||
if (digits.length === 10 && digits.startsWith('9')) digits = `0${digits}`;
|
||||
if (digits.length === 11 && digits.startsWith('9')) digits = `0${digits.slice(0, 10)}`;
|
||||
if (digits.length > 11 && digits.startsWith('09')) digits = digits.slice(0, 11);
|
||||
return digits;
|
||||
};
|
||||
|
||||
const cleanNationalId = (raw) => {
|
||||
if (!raw) return '';
|
||||
let digits = toEnglishDigits(raw).replace(/\D/g, '');
|
||||
if (digits && digits.length < 10 && /^\d+$/.test(digits)) {
|
||||
digits = digits.padStart(10, '0');
|
||||
}
|
||||
return digits;
|
||||
};
|
||||
|
||||
const cleanCard = (raw) => {
|
||||
if (!raw) return '';
|
||||
return toEnglishDigits(raw).replace(/\D/g, '');
|
||||
};
|
||||
|
||||
const cleanShaba = (raw) => {
|
||||
if (!raw) return '';
|
||||
let val = toEnglishDigits(raw).replace(/[^0-9A-Za-z]/g, '');
|
||||
return val;
|
||||
};
|
||||
|
||||
const main = () => {
|
||||
if (!fs.existsSync(ODS_FILE)) {
|
||||
console.error(`ODS file not found: ${ODS_FILE}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const rows = extractOdsRows(ODS_FILE);
|
||||
if (!rows || rows.length < 2) {
|
||||
console.error('No rows found in ODS file');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const header = rows[0];
|
||||
console.log('Detected headers:', header);
|
||||
|
||||
const professors = [];
|
||||
|
||||
for (let i = 1; i < rows.length; i += 1) {
|
||||
const r = rows[i];
|
||||
// 0: ردیف, 1: نام, 2: نام خانوادگی, 3: کد ملی, 4: شماره تماس, 5: درصد, 6: شماره کارت, 7: شمار شبا
|
||||
const rawName = r[1] || '';
|
||||
const rawSurname = r[2] || '';
|
||||
const rawNid = r[3] || '';
|
||||
const rawPhone = r[4] || '';
|
||||
const rawCard = r[6] || '';
|
||||
const rawShaba = r[7] || '';
|
||||
|
||||
// Strip honorifics like 'سرکار'
|
||||
const name = rawName.replace(/^(آقای|اقای|خانم|آقا|سرکار\s+خانم|سرکار)\s+/, '').trim();
|
||||
const surname = rawSurname.trim();
|
||||
|
||||
const nationalIdCode = cleanNationalId(rawNid);
|
||||
const phoneNumber = cleanPhone(rawPhone);
|
||||
const cardNumber = cleanCard(rawCard);
|
||||
const shabaNumber = cleanShaba(rawShaba);
|
||||
|
||||
professors.push({
|
||||
name,
|
||||
surname,
|
||||
nationalIdCode,
|
||||
phoneNumber,
|
||||
cardNumber,
|
||||
shabaNumber
|
||||
});
|
||||
}
|
||||
|
||||
const payload = {
|
||||
version: 1,
|
||||
generatedAt: new Date().toISOString(),
|
||||
source: 'Untitled spreadsheet.ods',
|
||||
summary: {
|
||||
professors: professors.length
|
||||
},
|
||||
professors
|
||||
};
|
||||
|
||||
fs.writeFileSync(OUTPUT_FILE, JSON.stringify(payload, null, 2), 'utf-8');
|
||||
console.log(`Successfully wrote ${professors.length} professors to ${OUTPUT_FILE}`);
|
||||
};
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
extractOdsRows,
|
||||
main
|
||||
};
|
||||
Reference in New Issue
Block a user