Add customers management module with database schema and validation
- Introduced `CustomersModule` to manage customer data, including read and write controllers. - Created database migrations for the `customers` and `customer_contacts` tables, including constraints and unique indexes. - Implemented validation for customer fields such as name, code, and address with corresponding utility functions. - Developed service and repository layers for handling customer data operations. - Added unit tests for the customers service, repository, and controllers to ensure functionality and correctness. - Updated application module to include the new `CustomersModule` for better organization.
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { CustomersWriteController } from './customers-write.controller';
|
||||
import { CustomersService } from './customers.service';
|
||||
|
||||
const createDto = {
|
||||
code: 'CUST_01',
|
||||
name: 'Acme Corp',
|
||||
phone: '+6281234567890',
|
||||
address: 'Jl Sudirman No 1',
|
||||
};
|
||||
|
||||
describe('CustomersWriteController', () => {
|
||||
let controller: CustomersWriteController;
|
||||
const service = {
|
||||
create: jest.fn(),
|
||||
update: jest.fn(),
|
||||
updateStatus: jest.fn(),
|
||||
delete: jest.fn(),
|
||||
bulkDelete: jest.fn(),
|
||||
bulkUpdateStatus: jest.fn(),
|
||||
importCsv: jest.fn(),
|
||||
addContact: jest.fn(),
|
||||
updateContact: jest.fn(),
|
||||
deleteContact: jest.fn(),
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks();
|
||||
const moduleRef: TestingModule = await Test.createTestingModule({
|
||||
controllers: [CustomersWriteController],
|
||||
providers: [{ provide: CustomersService, useValue: service }],
|
||||
}).compile();
|
||||
controller = moduleRef.get(CustomersWriteController);
|
||||
});
|
||||
|
||||
it('create passes dto fields and user id', async () => {
|
||||
service.create.mockResolvedValue({ id: 'cu-1' });
|
||||
await controller.create(createDto, 'user-1');
|
||||
expect(service.create).toHaveBeenCalledWith({
|
||||
...createDto,
|
||||
userId: 'user-1',
|
||||
});
|
||||
});
|
||||
|
||||
it('update, updateStatus, and delete delegate', async () => {
|
||||
service.update.mockResolvedValue({ id: 'cu-1' });
|
||||
service.updateStatus.mockResolvedValue({ id: 'cu-1' });
|
||||
service.delete.mockResolvedValue(undefined);
|
||||
await controller.update('cu-1', { name: 'Acme Corp' }, 'user-1');
|
||||
await controller.updateStatus('cu-1', { status: 'active' }, 'user-1');
|
||||
await controller.delete('cu-1');
|
||||
expect(service.updateStatus).toHaveBeenCalledWith(
|
||||
'cu-1',
|
||||
'active',
|
||||
'user-1',
|
||||
);
|
||||
expect(service.delete).toHaveBeenCalledWith('cu-1');
|
||||
});
|
||||
|
||||
it('nested contact routes delegate', async () => {
|
||||
service.addContact.mockResolvedValue({ id: 'cu-1' });
|
||||
service.updateContact.mockResolvedValue({ id: 'cu-1' });
|
||||
service.deleteContact.mockResolvedValue(undefined);
|
||||
await controller.addContact('cu-1', { name: 'Ada Lovelace' }, 'user-1');
|
||||
await controller.updateContact(
|
||||
'cu-1',
|
||||
'ct-1',
|
||||
{ jobTitle: 'Buyer' },
|
||||
'user-1',
|
||||
);
|
||||
await controller.deleteContact('cu-1', 'ct-1');
|
||||
expect(service.addContact).toHaveBeenCalledWith(
|
||||
'cu-1',
|
||||
{ name: 'Ada Lovelace' },
|
||||
'user-1',
|
||||
);
|
||||
expect(service.updateContact).toHaveBeenCalledWith('cu-1', 'ct-1', {
|
||||
jobTitle: 'Buyer',
|
||||
userId: 'user-1',
|
||||
});
|
||||
expect(service.deleteContact).toHaveBeenCalledWith('cu-1', 'ct-1');
|
||||
});
|
||||
|
||||
it('bulk and import delegate', async () => {
|
||||
service.bulkDelete.mockResolvedValue({ deleted: 1 });
|
||||
service.bulkUpdateStatus.mockResolvedValue({ updated: 1 });
|
||||
service.importCsv.mockResolvedValue({ imported: 1 });
|
||||
await controller.bulkDelete({ ids: ['cu-1'] });
|
||||
await controller.bulkStatus(
|
||||
{ ids: ['cu-1'], status: 'archived' },
|
||||
'user-1',
|
||||
);
|
||||
await controller.importCsv(
|
||||
{ buffer: Buffer.from('code,name\nCUST_01,Acme') },
|
||||
'user-1',
|
||||
);
|
||||
expect(service.importCsv).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('importCsv uses empty string when file is missing', async () => {
|
||||
service.importCsv.mockResolvedValue({ imported: 0 });
|
||||
await controller.importCsv(undefined, 'user-1');
|
||||
expect(service.importCsv).toHaveBeenCalledWith('', 'user-1');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user