240 lines
No EOL
6 KiB
JavaScript
240 lines
No EOL
6 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
const { budgetRepository, budgetItemRepository } = require('../repositories');
|
|
|
|
/**
|
|
* Check if site has access to budgeting feature (premium)
|
|
* Budgeting is available in Professional and Enterprise plans
|
|
*/
|
|
async function hasBudgetingAccess(site_id) {
|
|
// TODO: Implement subscription check
|
|
// For now, assume all sites have access for testing
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* GET /api/plugins/financials/budgets
|
|
* Get all budgets for a site
|
|
*/
|
|
router.get('/', async (req, res) => {
|
|
try {
|
|
const { site_id } = req.query;
|
|
|
|
if (!site_id) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'site_id query parameter is required'
|
|
});
|
|
}
|
|
|
|
// Check feature access
|
|
if (!(await hasBudgetingAccess(site_id))) {
|
|
return res.status(403).json({
|
|
success: false,
|
|
error: 'Budgeting feature not available',
|
|
message: 'Please upgrade to Professional or Enterprise plan to access budgeting features'
|
|
});
|
|
}
|
|
|
|
const budgets = await budgetRepository.findBySiteId(site_id);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: budgets,
|
|
message: 'Budgets retrieved successfully'
|
|
});
|
|
} catch (error) {
|
|
console.error('Failed to get budgets:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to retrieve budgets',
|
|
message: error.message
|
|
});
|
|
}
|
|
});
|
|
|
|
/**
|
|
* GET /api/plugins/financials/budgets/:id
|
|
* Get budget by ID
|
|
*/
|
|
router.get('/:id', async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const { site_id } = req.query;
|
|
|
|
if (!site_id) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'site_id is required'
|
|
});
|
|
}
|
|
|
|
// Check feature access
|
|
if (!(await hasBudgetingAccess(site_id))) {
|
|
return res.status(403).json({
|
|
success: false,
|
|
error: 'Budgeting feature not available',
|
|
message: 'Please upgrade to Professional or Enterprise plan to access budgeting features'
|
|
});
|
|
}
|
|
|
|
const budget = await budgetRepository.findById(id);
|
|
|
|
if (!budget) {
|
|
return res.status(404).json({
|
|
success: false,
|
|
error: 'Budget not found'
|
|
});
|
|
}
|
|
|
|
// Verify budget belongs to site
|
|
if (budget.site_id !== site_id) {
|
|
return res.status(403).json({
|
|
success: false,
|
|
error: 'Access denied'
|
|
});
|
|
}
|
|
|
|
// Get budget items
|
|
const items = await budgetItemRepository.findByBudgetId(id);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: {
|
|
...budget,
|
|
items
|
|
},
|
|
message: 'Budget details retrieved successfully'
|
|
});
|
|
} catch (error) {
|
|
console.error('Failed to get budget:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to retrieve budget',
|
|
message: error.message
|
|
});
|
|
}
|
|
});
|
|
|
|
/**
|
|
* POST /api/plugins/financials/budgets
|
|
* Create a new budget
|
|
*/
|
|
router.post('/', async (req, res) => {
|
|
try {
|
|
const { site_id, name, description, fiscal_year, start_date, end_date, total_amount, status, items, created_by } = req.body;
|
|
|
|
if (!site_id || !name || !fiscal_year || !start_date || !end_date || !total_amount) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'Missing required fields',
|
|
message: 'Site ID, name, fiscal year, start date, end date, and total amount are required'
|
|
});
|
|
}
|
|
|
|
// Check feature access
|
|
if (!(await hasBudgetingAccess(site_id))) {
|
|
return res.status(403).json({
|
|
success: false,
|
|
error: 'Budgeting feature not available',
|
|
message: 'Please upgrade to Professional or Enterprise plan to access budgeting features'
|
|
});
|
|
}
|
|
|
|
const budget = await budgetRepository.createBudget({
|
|
site_id,
|
|
name,
|
|
description,
|
|
fiscal_year,
|
|
start_date,
|
|
end_date,
|
|
total_amount,
|
|
status,
|
|
created_by: created_by || req.user?.id || 'system'
|
|
});
|
|
|
|
// Create budget items if provided
|
|
if (items && Array.isArray(items)) {
|
|
for (const item of items) {
|
|
await budgetItemRepository.createItem({
|
|
budget_id: budget.id,
|
|
account_id: item.account_id,
|
|
planned_amount: item.planned_amount,
|
|
notes: item.notes
|
|
});
|
|
}
|
|
}
|
|
|
|
res.status(201).json({
|
|
success: true,
|
|
data: budget,
|
|
message: 'Budget created successfully'
|
|
});
|
|
} catch (error) {
|
|
console.error('Failed to create budget:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to create budget',
|
|
message: error.message
|
|
});
|
|
}
|
|
});
|
|
|
|
/**
|
|
* POST /api/plugins/financials/budgets/:id/items
|
|
* Add budget item
|
|
*/
|
|
router.post('/:id/items', async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const { account_id, planned_amount, notes } = req.body;
|
|
const { site_id } = req.query;
|
|
|
|
if (!site_id) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'site_id is required'
|
|
});
|
|
}
|
|
|
|
// Validate required fields
|
|
if (!account_id || !planned_amount) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'Missing required fields',
|
|
message: 'Account ID and planned amount are required'
|
|
});
|
|
}
|
|
|
|
// Check feature access
|
|
if (!(await hasBudgetingAccess(site_id))) {
|
|
return res.status(403).json({
|
|
success: false,
|
|
error: 'Budgeting feature not available',
|
|
message: 'Please upgrade to Professional or Enterprise plan to access budgeting features'
|
|
});
|
|
}
|
|
|
|
const item = await budgetItemRepository.createItem({
|
|
budget_id: id,
|
|
account_id,
|
|
planned_amount,
|
|
notes
|
|
});
|
|
|
|
res.status(201).json({
|
|
success: true,
|
|
data: item,
|
|
message: 'Budget item added successfully'
|
|
});
|
|
} catch (error) {
|
|
console.error('Failed to add budget item:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to add budget item',
|
|
message: error.message
|
|
});
|
|
}
|
|
});
|
|
|
|
module.exports = router; |