- Add backend stale process monitoring API (/api/stale-processes) - Add users management route - Add frontend landing page and stale process monitor UI on /scraper-tools - Move old development scripts to backend/archive/ - Update frontend build with new features 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
166 lines
4.6 KiB
TypeScript
166 lines
4.6 KiB
TypeScript
import * as fs from 'fs';
|
|
|
|
async function previewImport() {
|
|
console.log('📋 Preview of AZDHS import data...\n');
|
|
|
|
const fileContent = fs.readFileSync('/home/kelly/Documents/azdhs dispos', 'utf-8');
|
|
const lines = fileContent.split('\n').map(l => l.trim()).filter(l => l.length > 0);
|
|
|
|
const dispensaries: any[] = [];
|
|
let i = 0;
|
|
|
|
while (i < lines.length) {
|
|
if (lines[i] === 'Get Details') {
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
if (i + 1 < lines.length && lines[i + 1] === 'Get Details') {
|
|
i += 2;
|
|
continue;
|
|
}
|
|
|
|
let name = lines[i];
|
|
let companyName = '';
|
|
let statusLine = '';
|
|
let address = '';
|
|
let linesConsumed = 0;
|
|
|
|
const nextLine = lines[i + 1] || '';
|
|
if (nextLine.includes('Operating')) {
|
|
companyName = name;
|
|
statusLine = lines[i + 1];
|
|
address = lines[i + 2];
|
|
const getDetails = lines[i + 3];
|
|
if (getDetails !== 'Get Details') {
|
|
i++;
|
|
continue;
|
|
}
|
|
linesConsumed = 4;
|
|
} else {
|
|
companyName = lines[i + 1];
|
|
statusLine = lines[i + 2];
|
|
address = lines[i + 3];
|
|
const getDetails = lines[i + 4];
|
|
if (getDetails !== 'Get Details') {
|
|
i++;
|
|
continue;
|
|
}
|
|
linesConsumed = 5;
|
|
}
|
|
|
|
// Parse phone from status line
|
|
let phone = '';
|
|
const phoneMatch = statusLine.match(/(\(\d{3}\)\s*\d{3}-\d{4}|\d{3}-\d{3}-\d{4}|\d{10})/);
|
|
if (phoneMatch) {
|
|
phone = phoneMatch[1].replace(/\D/g, '');
|
|
}
|
|
|
|
// Parse operating status and entity type
|
|
const statusParts = statusLine.split('·').map(p => p.trim());
|
|
const operatingStatus = statusParts[0] || '';
|
|
const entityType = statusParts[1] || '';
|
|
|
|
// Parse address components
|
|
let street = '', city = '', state = 'AZ', zip = '';
|
|
|
|
const addressParts = address.split(',').map(p => p.trim());
|
|
|
|
if (addressParts.length >= 3) {
|
|
street = addressParts.slice(0, -2).join(', ');
|
|
city = addressParts[addressParts.length - 2];
|
|
const stateZip = addressParts[addressParts.length - 1];
|
|
const stateZipMatch = stateZip.match(/([A-Z]{2})\s+(\d{5})/);
|
|
if (stateZipMatch) {
|
|
state = stateZipMatch[1];
|
|
zip = stateZipMatch[2];
|
|
}
|
|
} else if (addressParts.length === 2) {
|
|
street = addressParts[0];
|
|
const cityStateZip = addressParts[1];
|
|
const match = cityStateZip.match(/([^,]+),?\s+([A-Z]{2})\s+(\d{5})/);
|
|
if (match) {
|
|
city = match[1].trim();
|
|
state = match[2];
|
|
zip = match[3];
|
|
}
|
|
} else {
|
|
street = address;
|
|
const zipMatch = address.match(/\b(\d{5})\b/);
|
|
if (zipMatch) zip = zipMatch[1];
|
|
const cityMatch = address.match(/,\s*([A-Za-z\s]+),\s*AZ/);
|
|
if (cityMatch) city = cityMatch[1].trim();
|
|
}
|
|
|
|
dispensaries.push({
|
|
name,
|
|
companyName,
|
|
phone,
|
|
street,
|
|
city,
|
|
state,
|
|
zip,
|
|
operatingStatus,
|
|
entityType
|
|
});
|
|
|
|
i += linesConsumed;
|
|
}
|
|
|
|
console.log(`✅ Found ${dispensaries.length} dispensaries\n`);
|
|
|
|
// Show first 10
|
|
console.log('📋 First 10 dispensaries:\n');
|
|
console.table(dispensaries.slice(0, 10).map(d => ({
|
|
name: d.name.substring(0, 30),
|
|
company: d.companyName.substring(0, 30),
|
|
city: d.city,
|
|
phone: d.phone,
|
|
status: d.operatingStatus,
|
|
type: d.entityType.substring(0, 20)
|
|
})));
|
|
|
|
// Show last 10
|
|
console.log('\n📋 Last 10 dispensaries:\n');
|
|
console.table(dispensaries.slice(-10).map(d => ({
|
|
name: d.name.substring(0, 30),
|
|
company: d.companyName.substring(0, 30),
|
|
city: d.city,
|
|
phone: d.phone,
|
|
status: d.operatingStatus,
|
|
type: d.entityType.substring(0, 20)
|
|
})));
|
|
|
|
// Show counts by city
|
|
const cityCounts: any = {};
|
|
dispensaries.forEach(d => {
|
|
cityCounts[d.city] = (cityCounts[d.city] || 0) + 1;
|
|
});
|
|
|
|
console.log('\n📊 Dispensaries by city (top 10):\n');
|
|
const sortedCities = Object.entries(cityCounts)
|
|
.sort((a: any, b: any) => b[1] - a[1])
|
|
.slice(0, 10);
|
|
console.table(sortedCities.map(([city, count]) => ({ city, count })));
|
|
|
|
// Show entity types
|
|
const entityTypes: any = {};
|
|
dispensaries.forEach(d => {
|
|
entityTypes[d.entityType] = (entityTypes[d.entityType] || 0) + 1;
|
|
});
|
|
|
|
console.log('\n📊 Dispensaries by entity type:\n');
|
|
console.table(Object.entries(entityTypes).map(([type, count]) => ({ type, count })));
|
|
|
|
// Show operating status
|
|
const statuses: any = {};
|
|
dispensaries.forEach(d => {
|
|
statuses[d.operatingStatus] = (statuses[d.operatingStatus] || 0) + 1;
|
|
});
|
|
|
|
console.log('\n📊 Dispensaries by operating status:\n');
|
|
console.table(Object.entries(statuses).map(([status, count]) => ({ status, count })));
|
|
}
|
|
|
|
previewImport();
|