feat: add CashboxExportSubscription entity and service
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
import { TeamRolesEnum } from '../team-roles/team-roles.enum';
|
||||
import { RecurringTransactionIntervalEnum } from '../recurring-transactions/recurring-transaction-interval.enum';
|
||||
import { CashboxExportSubscriptionService } from './cashbox-export-subscription.service';
|
||||
|
||||
describe('CashboxExportSubscriptionService', () => {
|
||||
const repository = { findOne: jest.fn(), create: jest.fn((v) => v), save: jest.fn(async (v) => v) };
|
||||
const access = { assertAtLeast: jest.fn() };
|
||||
let service: CashboxExportSubscriptionService;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
service = new CashboxExportSubscriptionService(repository as any, access as any);
|
||||
});
|
||||
|
||||
it('returns a paused default when no subscription exists yet', async () => {
|
||||
repository.findOne.mockResolvedValue(null);
|
||||
|
||||
await expect(service.getSubscription(5, 42)).resolves.toEqual({
|
||||
recipients: [],
|
||||
interval: RecurringTransactionIntervalEnum.monthly,
|
||||
active: false,
|
||||
nextRunDate: null,
|
||||
});
|
||||
expect(access.assertAtLeast).toHaveBeenCalledWith(
|
||||
42,
|
||||
5,
|
||||
'transaction_create_min_role',
|
||||
TeamRolesEnum.scnd_treasurer,
|
||||
);
|
||||
});
|
||||
|
||||
it('returns the existing subscription', async () => {
|
||||
repository.findOne.mockResolvedValue({
|
||||
recipients: ['vorstand@example.com'],
|
||||
interval: RecurringTransactionIntervalEnum.yearly,
|
||||
active: true,
|
||||
nextRunDate: '2027-01-01T00:00:00.000Z',
|
||||
});
|
||||
|
||||
await expect(service.getSubscription(5, 42)).resolves.toEqual({
|
||||
recipients: ['vorstand@example.com'],
|
||||
interval: RecurringTransactionIntervalEnum.yearly,
|
||||
active: true,
|
||||
nextRunDate: '2027-01-01T00:00:00.000Z',
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects activating with an empty recipient list', async () => {
|
||||
repository.findOne.mockResolvedValue(null);
|
||||
|
||||
await expect(
|
||||
service.upsertSubscription(5, 42, {
|
||||
recipients: [],
|
||||
interval: RecurringTransactionIntervalEnum.monthly,
|
||||
active: true,
|
||||
}),
|
||||
).rejects.toBeInstanceOf(BadRequestException);
|
||||
expect(repository.save).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('creates a new subscription and computes the next period boundary on first activation', async () => {
|
||||
repository.findOne.mockResolvedValue(null);
|
||||
jest.useFakeTimers().setSystemTime(new Date('2026-08-15T10:00:00.000Z'));
|
||||
|
||||
const result = await service.upsertSubscription(5, 42, {
|
||||
recipients: ['vorstand@example.com'],
|
||||
interval: RecurringTransactionIntervalEnum.monthly,
|
||||
active: true,
|
||||
});
|
||||
|
||||
expect(result.nextRunDate).toBe('2026-09-01T00:00:00.000Z');
|
||||
expect(repository.save).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
recipients: ['vorstand@example.com'],
|
||||
interval: RecurringTransactionIntervalEnum.monthly,
|
||||
active: true,
|
||||
nextRunDate: '2026-09-01T00:00:00.000Z',
|
||||
}),
|
||||
);
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('keeps the existing nextRunDate when editing recipients without changing interval or activation state', async () => {
|
||||
repository.findOne.mockResolvedValue({
|
||||
recipients: ['old@example.com'],
|
||||
interval: RecurringTransactionIntervalEnum.monthly,
|
||||
active: true,
|
||||
nextRunDate: '2026-09-01T00:00:00.000Z',
|
||||
});
|
||||
|
||||
const result = await service.upsertSubscription(5, 42, {
|
||||
recipients: ['new@example.com'],
|
||||
interval: RecurringTransactionIntervalEnum.monthly,
|
||||
active: true,
|
||||
});
|
||||
|
||||
expect(result.nextRunDate).toBe('2026-09-01T00:00:00.000Z');
|
||||
});
|
||||
|
||||
it('recomputes nextRunDate when the interval changes', async () => {
|
||||
repository.findOne.mockResolvedValue({
|
||||
recipients: ['a@example.com'],
|
||||
interval: RecurringTransactionIntervalEnum.monthly,
|
||||
active: true,
|
||||
nextRunDate: '2026-09-01T00:00:00.000Z',
|
||||
});
|
||||
jest.useFakeTimers().setSystemTime(new Date('2026-08-15T10:00:00.000Z'));
|
||||
|
||||
const result = await service.upsertSubscription(5, 42, {
|
||||
recipients: ['a@example.com'],
|
||||
interval: RecurringTransactionIntervalEnum.yearly,
|
||||
active: true,
|
||||
});
|
||||
|
||||
expect(result.nextRunDate).toBe('2027-08-01T00:00:00.000Z');
|
||||
jest.useRealTimers();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user