feat(config): importar pacientes de planilha Google existente (somente-leitura)
- backend POST /api/clinica-sync/import-pacientes (le aba 'pacientes' de um ID/URL, nao altera sheets_id nem a planilha) - endpoint set-id (opcional) para apontar planilha de backup - frontend: campo de ID/URL + botao Importar no card Backup; rotulo Restaurar->Importar Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1023,6 +1023,55 @@ app.post('/api/clinica-sync/pull', tenantGuard, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Importa SOMENTE pacientes de uma planilha EXISTENTE (ID/URL), sem tocar no sheets_id
|
||||
// de backup (não-destrutivo: nunca limpa/sobrescreve a planilha fonte). Lê a aba "pacientes".
|
||||
app.post('/api/clinica-sync/import-pacientes', tenantGuard, async (req, res) => {
|
||||
const clinicaId = req.body?.clinicaId || req.query.clinicaId;
|
||||
let sheetsId = String(req.body?.sheetsId || '').trim();
|
||||
const logs = [];
|
||||
try {
|
||||
if (!clinicaId || !sheetsId) return res.status(400).json({ success: false, message: 'clinicaId e ID da planilha são obrigatórios.' });
|
||||
const m = sheetsId.match(/\/d\/([a-zA-Z0-9-_]+)/); if (m) sheetsId = m[1];
|
||||
const sheets = await getClinicSheetsClient(clinicaId);
|
||||
let title;
|
||||
try { const meta = await sheets.spreadsheets.get({ spreadsheetId: sheetsId, fields: 'properties.title' }); title = meta.data.properties.title; }
|
||||
catch { return res.status(400).json({ success: false, message: 'Não consegui abrir essa planilha. Confira o ID e se ela está compartilhada com a conta Google desta unidade.' }); }
|
||||
logs.push(`[←] LENDO "${title}" → ABA PACIENTES...`);
|
||||
const n = await pullClinicTable(CLINIC_SYNC_TABLES[0], sheets, sheetsId, clinicaId); // [0] = pacientes
|
||||
logs.push(`[✓] ${n} PACIENTES IMPORTADOS`);
|
||||
res.json({ success: true, imported: n, logs });
|
||||
} catch (err) {
|
||||
const msg = err.message === 'NO_GOOGLE_TOKEN' ? 'CONECTE A CONTA GOOGLE DESTA UNIDADE PRIMEIRO (AGENDA → CONFIGURAÇÕES).' : err.message;
|
||||
res.status(400).json({ success: false, message: msg, logs: [...logs, `[ERRO] ${msg}`] });
|
||||
}
|
||||
});
|
||||
|
||||
// Define a planilha (ID/URL) a ser usada por esta clínica → habilita IMPORTAR de uma
|
||||
// planilha EXISTENTE (ex.: migração de pacientes). Valida o acesso com a conta da unidade.
|
||||
app.post('/api/clinica-sync/set-id', tenantGuard, async (req, res) => {
|
||||
const clinicaId = req.body?.clinicaId || req.query.clinicaId;
|
||||
let sheetsId = String(req.body?.sheetsId || '').trim();
|
||||
try {
|
||||
if (!clinicaId || !sheetsId) return res.status(400).json({ success: false, message: 'clinicaId e ID da planilha são obrigatórios.' });
|
||||
const m = sheetsId.match(/\/d\/([a-zA-Z0-9-_]+)/); // aceita URL completa
|
||||
if (m) sheetsId = m[1];
|
||||
const sheets = await getClinicSheetsClient(clinicaId);
|
||||
let title, abas = [];
|
||||
try {
|
||||
const meta = await sheets.spreadsheets.get({ spreadsheetId: sheetsId, fields: 'properties.title,sheets.properties.title' });
|
||||
title = meta.data.properties.title;
|
||||
abas = (meta.data.sheets || []).map(s => s.properties.title);
|
||||
} catch {
|
||||
return res.status(400).json({ success: false, message: 'Não consegui abrir essa planilha. Confira o ID e se ela está compartilhada com a conta Google desta unidade (' + sheetsId + ').' });
|
||||
}
|
||||
await pool.query('UPDATE clinicas SET sheets_id = $1 WHERE id = $2', [sheetsId, clinicaId]);
|
||||
res.json({ success: true, spreadsheetId: sheetsId, spreadsheetUrl: clinicSheetUrl(sheetsId), title, abas });
|
||||
} catch (err) {
|
||||
const msg = err.message === 'NO_GOOGLE_TOKEN' ? 'CONECTE A CONTA GOOGLE DESTA UNIDADE PRIMEIRO (AGENDA → CONFIGURAÇÕES).' : err.message;
|
||||
res.status(400).json({ success: false, message: msg });
|
||||
}
|
||||
});
|
||||
|
||||
// --- GOOGLE AUTH ROUTES ---
|
||||
app.get('/api/auth/google/url', (req, res) => {
|
||||
if (!googleCreds.clientId || !googleCreds.clientSecret) {
|
||||
|
||||
Reference in New Issue
Block a user