237 lines
6.0 KiB
Markdown
237 lines
6.0 KiB
Markdown
# Chart of Accounts - Quick Fix Implementation Guide
|
|
|
|
**Priority**: 🔴 Critical fixes to make routes accessible and secure
|
|
|
|
---
|
|
|
|
## Fix 1: Register Routes in Main App
|
|
|
|
**File**: `src/integration/api-gateway/app.ts`
|
|
|
|
**Add after line 252**:
|
|
```typescript
|
|
import chartOfAccountsRoutes from '@/core/accounting/chart-of-accounts.routes';
|
|
|
|
// ... existing code ...
|
|
|
|
app.use('/api/accounting/chart-of-accounts', chartOfAccountsRoutes);
|
|
```
|
|
|
|
**Location**: Add around line 252, after `nostroVostroRoutes`.
|
|
|
|
---
|
|
|
|
## Fix 2: Fix Route Conflict
|
|
|
|
**File**: `src/core/accounting/chart-of-accounts.routes.ts`
|
|
|
|
**Problem**: `/initialize` route conflicts with `/:accountCode` route.
|
|
|
|
**Solution**: Move `/initialize` route BEFORE parameterized routes:
|
|
|
|
```typescript
|
|
const router = Router();
|
|
|
|
// ✅ Initialize route FIRST (before parameterized routes)
|
|
router.post('/initialize', async (req, res) => {
|
|
// ... existing code ...
|
|
});
|
|
|
|
// Then other routes
|
|
router.get('/', async (req, res) => {
|
|
// ... existing code ...
|
|
});
|
|
|
|
// Parameterized routes come last
|
|
router.get('/:accountCode', async (req, res) => {
|
|
// ... existing code ...
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## Fix 3: Add Basic Authentication
|
|
|
|
**File**: `src/core/accounting/chart-of-accounts.routes.ts`
|
|
|
|
**Add at top**:
|
|
```typescript
|
|
import { zeroTrustAuthMiddleware } from '@/integration/api-gateway/middleware/auth.middleware';
|
|
```
|
|
|
|
**Protect sensitive routes**:
|
|
```typescript
|
|
// Initialize - Admin only
|
|
router.post('/initialize',
|
|
zeroTrustAuthMiddleware,
|
|
async (req, res) => {
|
|
// Check if user has admin role
|
|
if (req.user?.role !== 'ADMIN') {
|
|
return res.status(403).json({ error: 'Admin access required' });
|
|
}
|
|
// ... existing code ...
|
|
}
|
|
);
|
|
|
|
// Create - Accountant/Admin
|
|
router.post('/',
|
|
zeroTrustAuthMiddleware,
|
|
async (req, res) => {
|
|
if (!['ACCOUNTANT', 'ADMIN'].includes(req.user?.role || '')) {
|
|
return res.status(403).json({ error: 'Insufficient permissions' });
|
|
}
|
|
// ... existing code ...
|
|
}
|
|
);
|
|
|
|
// Update - Accountant/Admin
|
|
router.put('/:accountCode',
|
|
zeroTrustAuthMiddleware,
|
|
async (req, res) => {
|
|
if (!['ACCOUNTANT', 'ADMIN'].includes(req.user?.role || '')) {
|
|
return res.status(403).json({ error: 'Insufficient permissions' });
|
|
}
|
|
// ... existing code ...
|
|
}
|
|
);
|
|
```
|
|
|
|
---
|
|
|
|
## Fix 4: Add Basic Input Validation
|
|
|
|
**File**: `src/core/accounting/chart-of-accounts.routes.ts`
|
|
|
|
**Add validation helper**:
|
|
```typescript
|
|
function validateAccountCode(code: string): boolean {
|
|
return /^\d{4,10}$/.test(code);
|
|
}
|
|
|
|
function validateCategory(category: string): boolean {
|
|
return ['ASSET', 'LIABILITY', 'EQUITY', 'REVENUE', 'EXPENSE', 'OTHER'].includes(category);
|
|
}
|
|
|
|
function validateNormalBalance(balance: string): boolean {
|
|
return ['DEBIT', 'CREDIT'].includes(balance);
|
|
}
|
|
```
|
|
|
|
**Add to POST route**:
|
|
```typescript
|
|
router.post('/', async (req, res) => {
|
|
try {
|
|
const { accountCode, accountName, category, normalBalance } = req.body;
|
|
|
|
// Validate required fields
|
|
if (!accountCode || !accountName || !category || !normalBalance) {
|
|
return res.status(400).json({ error: 'Missing required fields' });
|
|
}
|
|
|
|
// Validate format
|
|
if (!validateAccountCode(accountCode)) {
|
|
return res.status(400).json({ error: 'Account code must be 4-10 digits' });
|
|
}
|
|
|
|
if (!validateCategory(category)) {
|
|
return res.status(400).json({ error: 'Invalid category' });
|
|
}
|
|
|
|
if (!validateNormalBalance(normalBalance)) {
|
|
return res.status(400).json({ error: 'Normal balance must be DEBIT or CREDIT' });
|
|
}
|
|
|
|
const account = await chartOfAccountsService.createAccount(req.body);
|
|
res.status(201).json({ account });
|
|
} catch (error: any) {
|
|
res.status(400).json({ error: error.message });
|
|
}
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## Fix 5: Add Parent Account Validation
|
|
|
|
**File**: `src/core/accounting/chart-of-accounts.service.ts`
|
|
|
|
**Update `createAccount` method**:
|
|
```typescript
|
|
async createAccount(account: Omit<ChartOfAccount, 'id'>): Promise<ChartOfAccount> {
|
|
// Validate parent exists if provided
|
|
if (account.parentAccountCode) {
|
|
const parent = await this.getAccountByCode(account.parentAccountCode);
|
|
if (!parent) {
|
|
throw new Error(`Parent account ${account.parentAccountCode} not found`);
|
|
}
|
|
|
|
// Validate category matches parent
|
|
if (parent.category !== account.category) {
|
|
throw new Error(`Account category must match parent category (${parent.category})`);
|
|
}
|
|
|
|
// Validate level is parent level + 1
|
|
if (account.level !== parent.level + 1) {
|
|
throw new Error(`Account level must be ${parent.level + 1} (parent level + 1)`);
|
|
}
|
|
}
|
|
|
|
// Validate normal balance matches category
|
|
const expectedBalance = this.getExpectedNormalBalance(account.category);
|
|
if (account.normalBalance !== expectedBalance) {
|
|
throw new Error(`Normal balance for ${account.category} should be ${expectedBalance}`);
|
|
}
|
|
|
|
// ... rest of existing implementation
|
|
}
|
|
|
|
private getExpectedNormalBalance(category: AccountCategory): 'DEBIT' | 'CREDIT' {
|
|
switch (category) {
|
|
case AccountCategory.ASSET:
|
|
case AccountCategory.EXPENSE:
|
|
return 'DEBIT';
|
|
case AccountCategory.LIABILITY:
|
|
case AccountCategory.EQUITY:
|
|
case AccountCategory.REVENUE:
|
|
return 'CREDIT';
|
|
default:
|
|
return 'DEBIT';
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Testing the Fixes
|
|
|
|
After implementing fixes 1-3, test:
|
|
|
|
```bash
|
|
# Test route registration
|
|
curl http://localhost:3000/api/accounting/chart-of-accounts
|
|
|
|
# Test initialize (should require auth)
|
|
curl -X POST http://localhost:3000/api/accounting/chart-of-accounts/initialize
|
|
|
|
# Test create with validation
|
|
curl -X POST http://localhost:3000/api/accounting/chart-of-accounts \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"accountCode": "9999", "accountName": "Test Account"}'
|
|
# Should return validation error
|
|
```
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
These 5 fixes address the most critical issues:
|
|
|
|
1. ✅ Routes will be accessible
|
|
2. ✅ Route conflicts resolved
|
|
3. ✅ Basic security added
|
|
4. ✅ Input validation added
|
|
5. ✅ Data integrity improved
|
|
|
|
**Estimated Time**: 2-3 hours
|
|
**Priority**: 🔴 Critical
|