48ea61cdcc
- Product documentation in docs/products/ - Updated MEMORY.md with product info - quiXzoom Auth Core as AAMOS Identity product
194 lines
6.0 KiB
JavaScript
194 lines
6.0 KiB
JavaScript
/**
|
|
* Automation Routes — Schemalagda och event-baserade automationer
|
|
*/
|
|
|
|
import { Router } from 'express';
|
|
import pg from 'pg';
|
|
const { Pool } = pg;
|
|
|
|
const router = Router();
|
|
|
|
const pool = new Pool({
|
|
host: process.env.DB_HOST || 'localhost',
|
|
port: process.env.DB_PORT || 5432,
|
|
database: process.env.DB_NAME || 'wavult_identity',
|
|
user: process.env.DB_USER || 'wavult_admin',
|
|
password: process.env.DB_PASSWORD || 'wavult_admin'
|
|
});
|
|
|
|
// GET /api/automations
|
|
router.get('/', async (req, res) => {
|
|
try {
|
|
const result = await pool.query(
|
|
'SELECT * FROM automations ORDER BY created_at DESC'
|
|
);
|
|
res.json({ automations: result.rows });
|
|
} catch (e) {
|
|
res.status(500).json({ error: e.message });
|
|
}
|
|
});
|
|
|
|
// POST /api/automations
|
|
router.post('/', async (req, res) => {
|
|
try {
|
|
const { name, description, trigger_type, frequency, action } = req.body;
|
|
|
|
const result = await pool.query(`
|
|
INSERT INTO automations (name, description, trigger_type, frequency, action, is_active)
|
|
VALUES ($1, $2, $3, $4, $5, true)
|
|
RETURNING *
|
|
`, [name, description, trigger_type, frequency, action]);
|
|
|
|
res.status(201).json({ automation: result.rows[0] });
|
|
} catch (e) {
|
|
res.status(500).json({ error: e.message });
|
|
}
|
|
});
|
|
|
|
// POST /api/automations/:id/run
|
|
router.post('/:id/run', async (req, res) => {
|
|
try {
|
|
const result = await pool.query(
|
|
'SELECT * FROM automations WHERE id = $1',
|
|
[req.params.id]
|
|
);
|
|
|
|
if (result.rows.length === 0) {
|
|
return res.status(404).json({ error: 'Automation hittades inte' });
|
|
}
|
|
|
|
const automation = result.rows[0];
|
|
|
|
// Execute automation logic based on action
|
|
let executionResult;
|
|
switch (automation.action) {
|
|
case 'create_invoice':
|
|
executionResult = await runInvoiceAutomation(automation);
|
|
break;
|
|
case 'send_reminder':
|
|
executionResult = await runReminderAutomation(automation);
|
|
break;
|
|
case 'export_report':
|
|
executionResult = await runExportAutomation(automation);
|
|
break;
|
|
case 'backup':
|
|
executionResult = await runBackupAutomation(automation);
|
|
break;
|
|
default:
|
|
executionResult = { success: false, message: 'Okänd åtgärd' };
|
|
}
|
|
|
|
// Log execution
|
|
await pool.query(`
|
|
INSERT INTO automation_logs (automation_id, status, result, executed_at)
|
|
VALUES ($1, $2, $3, NOW())
|
|
`, [req.params.id, executionResult.success ? 'success' : 'failed', JSON.stringify(executionResult)]);
|
|
|
|
res.json(executionResult);
|
|
} catch (e) {
|
|
res.status(500).json({ error: e.message });
|
|
}
|
|
});
|
|
|
|
// POST /api/automations/:id/toggle
|
|
router.post('/:id/toggle', async (req, res) => {
|
|
try {
|
|
const result = await pool.query(`
|
|
UPDATE automations
|
|
SET is_active = NOT is_active
|
|
WHERE id = $1
|
|
RETURNING *
|
|
`, [req.params.id]);
|
|
|
|
if (result.rows.length === 0) {
|
|
return res.status(404).json({ error: 'Automation hittades inte' });
|
|
}
|
|
|
|
res.json({ automation: result.rows[0] });
|
|
} catch (e) {
|
|
res.status(500).json({ error: e.message });
|
|
}
|
|
});
|
|
|
|
// Automation execution functions
|
|
async function runInvoiceAutomation(automation) {
|
|
// Find agreements that need invoicing
|
|
const agreements = await pool.query(`
|
|
SELECT a.*, c.name as customer_name, c.email as customer_email
|
|
FROM billing_agreements a
|
|
JOIN billing_customers c ON a.customer_id = c.id
|
|
WHERE a.status = 'active'
|
|
AND a.next_invoice_date <= NOW()
|
|
`);
|
|
|
|
const invoices = [];
|
|
for (const agreement of agreements.rows) {
|
|
// Create invoice for agreement
|
|
const invoiceResult = await pool.query(`
|
|
INSERT INTO billing_invoices
|
|
(invoice_number, customer_id, customer_name, customer_email,
|
|
invoice_date, due_date, status, subtotal, vat_total, total, amount_due)
|
|
VALUES (
|
|
(SELECT 'F-' || EXTRACT(YEAR FROM NOW()) || '-' || LPAD((COUNT(*) + 1)::text, 4, '0') FROM billing_invoices WHERE created_at >= DATE_TRUNC('year', NOW())),
|
|
$1, $2, $3, NOW(), NOW() + INTERVAL '30 days', 'draft', $4, $5, $6, $6
|
|
)
|
|
RETURNING *
|
|
`, [agreement.customer_id, agreement.customer_name, agreement.customer_email,
|
|
agreement.amount, agreement.amount * 0.25, agreement.amount * 1.25]);
|
|
|
|
invoices.push(invoiceResult.rows[0]);
|
|
|
|
// Update next invoice date
|
|
await pool.query(`
|
|
UPDATE billing_agreements
|
|
SET next_invoice_date = CASE billing_frequency
|
|
WHEN 'monthly' THEN next_invoice_date + INTERVAL '1 month'
|
|
WHEN 'quarterly' THEN next_invoice_date + INTERVAL '3 months'
|
|
WHEN 'semi_annual' THEN next_invoice_date + INTERVAL '6 months'
|
|
WHEN 'annual' THEN next_invoice_date + INTERVAL '1 year'
|
|
END
|
|
WHERE id = $1
|
|
`, [agreement.id]);
|
|
}
|
|
|
|
return { success: true, message: `Skapade ${invoices.length} fakturor`, invoices };
|
|
}
|
|
|
|
async function runReminderAutomation(automation) {
|
|
// Find overdue invoices
|
|
const invoices = await pool.query(`
|
|
SELECT i.*, c.email as customer_email
|
|
FROM billing_invoices i
|
|
JOIN billing_customers c ON i.customer_id = c.id
|
|
WHERE i.status IN ('sent', 'partially_paid')
|
|
AND i.due_date < NOW() - INTERVAL '7 days'
|
|
AND (i.last_reminder_at IS NULL OR i.last_reminder_at < NOW() - INTERVAL '7 days')
|
|
`);
|
|
|
|
const reminders = [];
|
|
for (const invoice of invoices.rows) {
|
|
// Send reminder (would integrate with email service)
|
|
await pool.query(`
|
|
UPDATE billing_invoices
|
|
SET reminder_count = reminder_count + 1, last_reminder_at = NOW()
|
|
WHERE id = $1
|
|
`, [invoice.id]);
|
|
|
|
reminders.push(invoice);
|
|
}
|
|
|
|
return { success: true, message: `Skickade ${reminders.length} påminnelser`, reminders };
|
|
}
|
|
|
|
async function runExportAutomation(automation) {
|
|
// Would integrate with export service
|
|
return { success: true, message: 'Rapport exporterad' };
|
|
}
|
|
|
|
async function runBackupAutomation(automation) {
|
|
// Would integrate with backup service
|
|
return { success: true, message: 'Backup slutförd' };
|
|
}
|
|
|
|
export default router;
|