diff --git a/backend/db.js b/backend/db.js index 739b70b..05e0870 100644 --- a/backend/db.js +++ b/backend/db.js @@ -84,11 +84,25 @@ CREATE TABLE IF NOT EXISTS agent_configs ( UNIQUE(tenant_id, agent_type) ); +CREATE TABLE IF NOT EXISTS prescriptions ( + id TEXT PRIMARY KEY, + tenant_id TEXT REFERENCES tenants(id) ON DELETE CASCADE, + doctor_id INTEGER REFERENCES users(id), + patient_id TEXT NOT NULL, + patient_name TEXT NOT NULL, + diagnosis TEXT, + medicines JSONB DEFAULT '[]', + lab_tests JSONB DEFAULT '[]', + status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'ready', 'dispensed')), + created_at TIMESTAMPTZ DEFAULT now() +); + CREATE INDEX IF NOT EXISTS idx_users_tenant ON users(tenant_id); CREATE INDEX IF NOT EXISTS idx_users_email ON users(email); CREATE INDEX IF NOT EXISTS idx_pending_status ON pending_registrations(status); CREATE INDEX IF NOT EXISTS idx_transactions_order ON transactions(order_id); CREATE INDEX IF NOT EXISTS idx_agent_configs_tenant ON agent_configs(tenant_id); +CREATE INDEX IF NOT EXISTS idx_prescriptions_tenant_status ON prescriptions(tenant_id, status); -- Migrations for existing DBs diff --git a/backend/prescriptionManager.js b/backend/prescriptionManager.js index aaa1380..9d23182 100644 --- a/backend/prescriptionManager.js +++ b/backend/prescriptionManager.js @@ -1,35 +1,68 @@ /** - * PrescriptionManager: Handles digital prescription generation. + * PrescriptionManager: Handles digital prescription generation and storage in PostgreSQL. */ +const db = require('./db'); class PrescriptionManager { - constructor() { - this.prescriptions = []; - } - - generate(patientId, doctorId, medicines, diagnosis, labTests = []) { + /** + * Create a new prescription + */ + async generate(tenantId, doctorId, patientId, patientName, diagnosis, medicines = [], labTests = []) { const id = `RX-${Date.now()}`; - const prescription = { - id, - patientId, - doctorId, - date: new Date().toISOString(), - diagnosis, - medicines, // Array of { name, dosage, frequency, duration, qty } - labTests // Array of { testName, instructions } - }; - - this.prescriptions.push(prescription); - + const query = ` + INSERT INTO prescriptions (id, tenant_id, doctor_id, patient_id, patient_name, diagnosis, medicines, lab_tests, status) + VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb, $8::jsonb, 'pending') + RETURNING *; + `; + const values = [ + id, tenantId, doctorId, patientId, patientName, diagnosis, + JSON.stringify(medicines), JSON.stringify(labTests) + ]; + + const res = await db.query(query, values); + const prescription = res.rows[0]; + + // Ensure we format it properly for the whatsapp message + const whatsappMessage = `💊 *Digital Prescription from Curio*\n\n*Patient:* ${patientName}\n*Diagnosis:* ${diagnosis}\n\n*Medicines:*\n${medicines.map(m => `- ${m.name}: ${m.dosage} (${m.frequency}) for ${m.duration}`).join('\n')}\n\n` + + (labTests.length > 0 ? `🔬 *Lab Tests Recommended:*\n${labTests.map(t => `- ${t.testName}`).join('\n')}\n\n` : "") + + `_You can show this message at our pharmacy for a 10% discount._`; + return { success: true, prescriptionId: id, data: prescription, - whatsappMessage: `💊 *Digital Prescription from Dr. Sharma*\n\n*Diagnosis:* ${diagnosis}\n\n*Medicines:*\n${medicines.map(m => `- ${m.name}: ${m.dosage} (${m.frequency}) for ${m.duration}`).join('\n')}\n\n` + - (labTests.length > 0 ? `🔬 *Lab Tests Recommended:*\n${labTests.map(t => `- ${t.testName}`).join('\n')}\n\n` : "") + - `_You can show this message at our pharmacy for a 10% discount._` + whatsappMessage }; } + + /** + * Get pending prescriptions for a tenant (used by Pharmacy) + */ + async getPending(tenantId) { + const query = ` + SELECT p.*, u.name as doctor_name + FROM prescriptions p + LEFT JOIN users u ON p.doctor_id = u.id + WHERE p.tenant_id = $1 AND p.status = 'pending' + ORDER BY p.created_at ASC; + `; + const res = await db.query(query, [tenantId]); + return res.rows; + } + + /** + * Update prescription status + */ + async updateStatus(tenantId, id, status) { + const query = ` + UPDATE prescriptions + SET status = $1 + WHERE id = $2 AND tenant_id = $3 + RETURNING *; + `; + const res = await db.query(query, [status, id, tenantId]); + return res.rows.length > 0 ? res.rows[0] : null; + } } module.exports = new PrescriptionManager(); diff --git a/backend/server.js b/backend/server.js index fbfa202..31d801f 100644 --- a/backend/server.js +++ b/backend/server.js @@ -14,6 +14,7 @@ const { signToken, requireAuth } = require('./authMiddleware'); const Razorpay = require('razorpay'); const { upload, initStorage, uploadFile } = require('./storage'); const AgentManager = require('./agents/AgentManager'); +const prescriptionManager = require('./prescriptionManager'); const razorpayInstance = new Razorpay({ key_id: process.env.RAZORPAY_KEY_ID || 'rzp_test_dummy_key_id', @@ -84,6 +85,7 @@ app.get('/admin', (req, res) => sendHtmlPage(res, 'admin.html')); app.get('/dashboard', (req, res) => sendHtmlPage(res, 'dashboard.html')); app.get('/register', (req, res) => sendHtmlPage(res, 'register.html')); app.get('/super-admin', (req, res) => sendHtmlPage(res, 'super-admin.html')); +app.get('/doctor-dashboard', (req, res) => sendHtmlPage(res, 'doctor-dashboard.html')); // ── Multi-tenant Config API (DB-first, fallback to in-memory) ───────────────── @@ -808,6 +810,54 @@ app.get('/api/ai/lab/alerts/:patientId', async (req, res) => { } }); +// ── Prescriptions API ───────────────────────────────────────────────────────── + +app.post('/api/prescriptions', requireAuth('DOCTOR'), async (req, res) => { + try { + const { patientId, patientName, diagnosis, medicines, labTests } = req.body; + const tenantId = req.user.tenantId; + const doctorId = req.user.id; + + const result = await prescriptionManager.generate(tenantId, doctorId, patientId, patientName, diagnosis, medicines, labTests); + + // Push notification via whatsappService (optional) + if (whatsappService && whatsappService.sendMessage && req.body.patientPhone) { + await whatsappService.sendMessage(req.body.patientPhone, result.whatsappMessage); + } + + res.json(result); + } catch (error) { + console.error('[Prescription API] Error:', error); + res.status(500).json({ error: 'Failed to create prescription' }); + } +}); + +app.get('/api/prescriptions/pending', requireAuth(), async (req, res) => { + try { + const tenantId = req.user.tenantId; + const pending = await prescriptionManager.getPending(tenantId); + res.json({ success: true, prescriptions: pending }); + } catch (error) { + console.error('[Prescription API] Error:', error); + res.status(500).json({ error: 'Failed to fetch pending prescriptions' }); + } +}); + +app.post('/api/prescriptions/:id/status', requireAuth(), async (req, res) => { + try { + const tenantId = req.user.tenantId; + const { status } = req.body; + const updated = await prescriptionManager.updateStatus(tenantId, req.params.id, status); + if (!updated) { + return res.status(404).json({ error: 'Prescription not found' }); + } + res.json({ success: true, prescription: updated }); + } catch (error) { + console.error('[Prescription API] Error:', error); + res.status(500).json({ error: 'Failed to update prescription status' }); + } +}); + // ── START ───────────────────────────────────────────────────────────────────── initSchema().then(() => { diff --git a/doctor-dashboard.html b/doctor-dashboard.html new file mode 100644 index 0000000..39ea145 --- /dev/null +++ b/doctor-dashboard.html @@ -0,0 +1,228 @@ + + + + + + Doctor Dashboard | Curio HMS + + + + + + + + + + + + +
+
+
+

Doctor Dashboard

+

Record details, prescribe medicines, and send to pharmacy.

+
+
+ + +
+
+ +
+ + +
+
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+ +
+ +
+ +
+
+
+
+ + + + diff --git a/pharmacy.html b/pharmacy.html index 2c39492..eb598de 100644 --- a/pharmacy.html +++ b/pharmacy.html @@ -84,23 +84,8 @@ Actions - - - #RX-901 - Suresh Kumar - Amoxicillin, Paracetamol - Dr. Sharma - Waiting for Dispense - - - - #RX-902 - Anjali Singh - Thyroxine 50mcg - Dr. Sharma - Ready - - + + Loading prescriptions... @@ -127,5 +112,53 @@ + +