347 lines
10 KiB
JavaScript
347 lines
10 KiB
JavaScript
/**
|
|
* Chart of Accounts Route Tests
|
|
*
|
|
* Tests for `/api/plugins/financials/accounts` endpoints
|
|
* Uses REAL PostgreSQL database - NO mocks
|
|
*/
|
|
|
|
const request = require('supertest');
|
|
const express = require('express');
|
|
const accountsRouter = require('../../routes/accounts');
|
|
const FinancialTestHelper = require('../helpers/testHelper');
|
|
|
|
describe('Chart of Accounts Routes', () => {
|
|
let app;
|
|
let testHelper;
|
|
let testSite;
|
|
let testUserId;
|
|
let chartOfAccountsRepository;
|
|
|
|
beforeAll(async () => {
|
|
// Create Express app for testing
|
|
app = express();
|
|
app.use(express.json());
|
|
app.use('/api/plugins/financials', accountsRouter);
|
|
|
|
// Initialize test helper
|
|
testHelper = new FinancialTestHelper();
|
|
|
|
// Create test data
|
|
testSite = await testHelper.createTestSite();
|
|
testUserId = testHelper.userId;
|
|
|
|
// Import repository
|
|
chartOfAccountsRepository = require('../../repositories').chartOfAccountsRepository;
|
|
});
|
|
|
|
afterAll(async () => {
|
|
// Cleanup handled by global schema manager
|
|
});
|
|
|
|
describe('GET /api/plugins/financials/accounts', () => {
|
|
it('should return all accounts for a site', async () => {
|
|
// Create test accounts
|
|
const accountsData = [
|
|
{
|
|
site_id: testSite.id,
|
|
account_code: '1000',
|
|
account_name: 'Cash Account',
|
|
account_type: 'asset',
|
|
description: 'Cash and cash equivalents',
|
|
is_active: true,
|
|
created_by: testUserId
|
|
},
|
|
{
|
|
site_id: testSite.id,
|
|
account_code: '2000',
|
|
account_name: 'Accounts Payable',
|
|
account_type: 'liability',
|
|
description: 'Amounts owed to vendors',
|
|
is_active: true,
|
|
created_by: testUserId
|
|
}
|
|
];
|
|
|
|
// Insert accounts using repository
|
|
for (const account of accountsData) {
|
|
await chartOfAccountsRepository.create(account);
|
|
}
|
|
|
|
const response = await request(app)
|
|
.get('/api/plugins/financials/accounts')
|
|
.query({ site_id: testSite.id });
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.data).toBeInstanceOf(Array);
|
|
expect(response.body.data.length).toBeGreaterThanOrEqual(2);
|
|
|
|
// Verify account structure matches expected format
|
|
const account = response.body.data.find(a => a.account_code === '1000');
|
|
expect(account).toBeDefined();
|
|
expect(account.account_name).toBe('Cash Account');
|
|
expect(account.account_type).toBe('asset');
|
|
});
|
|
|
|
it('should return empty array if no accounts exist', async () => {
|
|
// Create a different site with no accounts
|
|
const anotherSite = await testHelper.createTestSite();
|
|
|
|
const response = await request(app)
|
|
.get('/api/plugins/financials/accounts')
|
|
.query({ site_id: anotherSite.id });
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.data).toEqual([]);
|
|
});
|
|
|
|
it('should filter accounts by active status', async () => {
|
|
// Create active and inactive accounts
|
|
await chartOfAccountsRepository.create({
|
|
site_id: testSite.id,
|
|
account_code: '3000',
|
|
account_name: 'Active Account',
|
|
account_type: 'asset',
|
|
is_active: true,
|
|
created_by: testUserId
|
|
});
|
|
|
|
await chartOfAccountsRepository.create({
|
|
site_id: testSite.id,
|
|
account_code: '4000',
|
|
account_name: 'Inactive Account',
|
|
account_type: 'asset',
|
|
is_active: false,
|
|
created_by: testUserId
|
|
});
|
|
|
|
const response = await request(app)
|
|
.get('/api/plugins/financials/accounts')
|
|
.query({ site_id: testSite.id });
|
|
|
|
expect(response.status).toBe(200);
|
|
// Should include both active and inactive (implementation detail)
|
|
expect(response.body.data.length).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe('GET /api/plugins/financials/accounts/:id', () => {
|
|
let testAccount;
|
|
|
|
beforeEach(async () => {
|
|
// Create a test account
|
|
testAccount = await chartOfAccountsRepository.create({
|
|
site_id: testSite.id,
|
|
account_code: '5000',
|
|
account_name: 'Test Account',
|
|
account_type: 'equity',
|
|
description: 'Test account for detailed view',
|
|
is_active: true,
|
|
created_by: testUserId
|
|
});
|
|
});
|
|
|
|
it('should return account details by ID', async () => {
|
|
const response = await request(app)
|
|
.get(`/api/plugins/financials/accounts/${testAccount.id}`)
|
|
.query({ site_id: testSite.id });
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.data).toBeDefined();
|
|
expect(response.body.data.id).toBe(testAccount.id);
|
|
expect(response.body.data.account_code).toBe('5000');
|
|
expect(response.body.data.account_name).toBe('Test Account');
|
|
});
|
|
|
|
it('should return 404 for non-existent account', async () => {
|
|
const fakeId = '00000000-0000-0000-0000-000000000000';
|
|
const response = await request(app)
|
|
.get(`/api/plugins/financials/accounts/${fakeId}`)
|
|
.query({ site_id: testSite.id });
|
|
|
|
expect(response.status).toBe(404);
|
|
});
|
|
});
|
|
|
|
describe('POST /api/plugins/financials/accounts', () => {
|
|
it('should create a new account', async () => {
|
|
const newAccount = {
|
|
site_id: testSite.id,
|
|
account_code: '6000',
|
|
account_name: 'New Test Account',
|
|
account_type: 'expense',
|
|
description: 'Test expense account',
|
|
is_active: true
|
|
};
|
|
|
|
const response = await request(app)
|
|
.post('/api/plugins/financials/accounts')
|
|
.send(newAccount);
|
|
|
|
expect(response.status).toBe(201);
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.data).toBeDefined();
|
|
expect(response.body.data.account_code).toBe('6000');
|
|
expect(response.body.data.account_name).toBe('New Test Account');
|
|
});
|
|
|
|
it('should reject duplicate account codes for same site', async () => {
|
|
const account1 = {
|
|
site_id: testSite.id,
|
|
account_code: '7000',
|
|
account_name: 'First Account',
|
|
account_type: 'asset',
|
|
is_active: true
|
|
};
|
|
|
|
await request(app)
|
|
.post('/api/plugins/financials/accounts')
|
|
.send(account1);
|
|
|
|
// Try to create another with same code
|
|
const account2 = {
|
|
site_id: testSite.id,
|
|
account_code: '7000',
|
|
account_name: 'Duplicate Account',
|
|
account_type: 'asset',
|
|
is_active: true
|
|
};
|
|
|
|
const response = await request(app)
|
|
.post('/api/plugins/financials/accounts')
|
|
.send(account2);
|
|
|
|
// Should fail validation
|
|
expect(response.status).toBeGreaterThanOrEqual(400);
|
|
});
|
|
|
|
it('should require all required fields', async () => {
|
|
const incompleteAccount = {
|
|
site_id: testSite.id,
|
|
account_name: 'Incomplete Account'
|
|
// Missing account_code and account_type
|
|
};
|
|
|
|
const response = await request(app)
|
|
.post('/api/plugins/financials/accounts')
|
|
.send(incompleteAccount);
|
|
|
|
expect(response.status).toBe(400);
|
|
});
|
|
});
|
|
|
|
describe('PUT /api/plugins/financials/accounts/:id', () => {
|
|
let testAccount;
|
|
|
|
beforeEach(async () => {
|
|
testAccount = await chartOfAccountsRepository.create({
|
|
site_id: testSite.id,
|
|
account_code: '8000',
|
|
account_name: 'Original Name',
|
|
account_type: 'revenue',
|
|
description: 'Original description',
|
|
is_active: true,
|
|
created_by: testUserId
|
|
});
|
|
});
|
|
|
|
it('should update account details', async () => {
|
|
const updateData = {
|
|
account_name: 'Updated Name',
|
|
description: 'Updated description',
|
|
is_active: false
|
|
};
|
|
|
|
const response = await request(app)
|
|
.put(`/api/plugins/financials/accounts/${testAccount.id}`)
|
|
.send(updateData);
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.data.account_name).toBe('Updated Name');
|
|
expect(response.body.data.description).toBe('Updated description');
|
|
expect(response.body.data.is_active).toBe(false);
|
|
});
|
|
|
|
it('should return 404 for non-existent account', async () => {
|
|
const fakeId = '00000000-0000-0000-0000-000000000000';
|
|
const response = await request(app)
|
|
.put(`/api/plugins/financials/accounts/${fakeId}`)
|
|
.send({ account_name: 'Test' });
|
|
|
|
expect(response.status).toBe(404);
|
|
});
|
|
});
|
|
|
|
describe('DELETE /api/plugins/financials/accounts/:id', () => {
|
|
let testAccount;
|
|
|
|
beforeEach(async () => {
|
|
testAccount = await chartOfAccountsRepository.create({
|
|
site_id: testSite.id,
|
|
account_code: '9000',
|
|
account_name: 'Account to Delete',
|
|
account_type: 'asset',
|
|
is_active: true,
|
|
created_by: testUserId
|
|
});
|
|
});
|
|
|
|
it('should delete an account', async () => {
|
|
const response = await request(app)
|
|
.delete(`/api/plugins/financials/accounts/${testAccount.id}`);
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body.success).toBe(true);
|
|
|
|
// Verify account is deleted
|
|
const deletedAccount = await chartOfAccountsRepository.findById(testAccount.id);
|
|
expect(deletedAccount).toBeUndefined();
|
|
});
|
|
|
|
it('should return 404 for non-existent account', async () => {
|
|
const fakeId = '00000000-0000-0000-0000-000000000000';
|
|
const response = await request(app)
|
|
.delete(`/api/plugins/financials/accounts/${fakeId}`);
|
|
|
|
expect(response.status).toBe(404);
|
|
});
|
|
});
|
|
|
|
describe('GET /api/plugins/financials/accounts/:id/balance', () => {
|
|
let testAccount;
|
|
|
|
beforeEach(async () => {
|
|
testAccount = await chartOfAccountsRepository.create({
|
|
site_id: testSite.id,
|
|
account_code: '10000',
|
|
account_name: 'Balance Test Account',
|
|
account_type: 'asset',
|
|
is_active: true,
|
|
created_by: testUserId
|
|
});
|
|
});
|
|
|
|
it('should return account balance calculation', async () => {
|
|
const response = await request(app)
|
|
.get(`/api/plugins/financials/accounts/${testAccount.id}/balance`)
|
|
.query({
|
|
site_id: testSite.id,
|
|
start_date: '2024-01-01',
|
|
end_date: '2024-12-31'
|
|
});
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.data).toBeDefined();
|
|
expect(response.body.data.account_id).toBeDefined();
|
|
// Balance calculation structure should exist
|
|
// (exact structure depends on implementation)
|
|
});
|
|
});
|
|
});
|
|
|
|
|
|
|