feat: add cashbox export subscription endpoints
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
Param,
|
||||
ParseIntPipe,
|
||||
Put,
|
||||
Query,
|
||||
Request,
|
||||
Res,
|
||||
@@ -12,7 +14,9 @@ import { AuthGuard } from '@nestjs/passport';
|
||||
import { ApiBearerAuth } from '@nestjs/swagger';
|
||||
import type { Response } from 'express';
|
||||
import { CashboxExportQueryDto } from './dto/cashbox-export-query.dto';
|
||||
import { UpsertCashboxExportSubscriptionDTO } from './dto/upsert-cashbox-export-subscription.dto';
|
||||
import { CashboxExportService } from './cashbox-export.service';
|
||||
import { CashboxExportSubscriptionService } from './cashbox-export-subscription.service';
|
||||
|
||||
type AuthenticatedRequest = { user: { id: number } };
|
||||
|
||||
@@ -20,7 +24,10 @@ type AuthenticatedRequest = { user: { id: number } };
|
||||
@UseGuards(AuthGuard('jwt'))
|
||||
@Controller({ path: 'cashbox-export', version: '1' })
|
||||
export class CashboxExportController {
|
||||
constructor(private readonly service: CashboxExportService) {}
|
||||
constructor(
|
||||
private readonly service: CashboxExportService,
|
||||
private readonly subscriptionService: CashboxExportSubscriptionService,
|
||||
) {}
|
||||
|
||||
@Get(':teamId')
|
||||
async exportCashbox(
|
||||
@@ -42,4 +49,21 @@ export class CashboxExportController {
|
||||
});
|
||||
res.send(buffer);
|
||||
}
|
||||
|
||||
@Get(':teamId/subscription')
|
||||
getSubscription(
|
||||
@Request() request: AuthenticatedRequest,
|
||||
@Param('teamId', ParseIntPipe) teamId: number,
|
||||
) {
|
||||
return this.subscriptionService.getSubscription(teamId, request.user.id);
|
||||
}
|
||||
|
||||
@Put(':teamId/subscription')
|
||||
upsertSubscription(
|
||||
@Request() request: AuthenticatedRequest,
|
||||
@Param('teamId', ParseIntPipe) teamId: number,
|
||||
@Body() dto: UpsertCashboxExportSubscriptionDTO,
|
||||
) {
|
||||
return this.subscriptionService.upsertSubscription(teamId, request.user.id, dto);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,20 +7,29 @@ import {
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { RecurringTransactionIntervalEnum } from '../recurring-transactions/recurring-transaction-interval.enum';
|
||||
import validationOptions from '../utils/validation-options';
|
||||
import { CashboxExportController } from './cashbox-export.controller';
|
||||
import { CashboxExportService } from './cashbox-export.service';
|
||||
import { CashboxExportSubscriptionService } from './cashbox-export-subscription.service';
|
||||
|
||||
describe('cashbox export HTTP boundary', () => {
|
||||
let app: INestApplication;
|
||||
const service = {
|
||||
exportForUser: jest.fn(),
|
||||
};
|
||||
const subscriptionService = {
|
||||
getSubscription: jest.fn(),
|
||||
upsertSubscription: jest.fn(),
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
controllers: [CashboxExportController],
|
||||
providers: [{ provide: CashboxExportService, useValue: service }],
|
||||
providers: [
|
||||
{ provide: CashboxExportService, useValue: service },
|
||||
{ provide: CashboxExportSubscriptionService, useValue: subscriptionService },
|
||||
],
|
||||
})
|
||||
.overrideGuard(AuthGuard('jwt'))
|
||||
.useValue({
|
||||
@@ -95,4 +104,52 @@ describe('cashbox export HTTP boundary', () => {
|
||||
expect(response.headers['content-type']).toBe('application/pdf');
|
||||
expect(Buffer.from(response.body).equals(pdfBuffer)).toBe(true);
|
||||
});
|
||||
|
||||
it('reads the current subscription', async () => {
|
||||
const subscription = {
|
||||
recipients: ['vorstand@example.com'],
|
||||
interval: RecurringTransactionIntervalEnum.monthly,
|
||||
active: true,
|
||||
nextRunDate: '2026-09-01T00:00:00.000Z',
|
||||
};
|
||||
subscriptionService.getSubscription.mockResolvedValue(subscription);
|
||||
|
||||
await request(app.getHttpServer())
|
||||
.get('/api/v1/cashbox-export/5/subscription')
|
||||
.set('Authorization', 'Bearer user')
|
||||
.expect(200)
|
||||
.expect(subscription);
|
||||
expect(subscriptionService.getSubscription).toHaveBeenCalledWith(5, 42);
|
||||
});
|
||||
|
||||
it('rejects an invalid recipient email on upsert', async () => {
|
||||
await request(app.getHttpServer())
|
||||
.put('/api/v1/cashbox-export/5/subscription')
|
||||
.set('Authorization', 'Bearer user')
|
||||
.send({ recipients: ['not-an-email'], interval: 'monthly', active: true })
|
||||
.expect(422);
|
||||
expect(subscriptionService.upsertSubscription).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('accepts a valid subscription upsert', async () => {
|
||||
const subscription = {
|
||||
recipients: ['vorstand@example.com'],
|
||||
interval: RecurringTransactionIntervalEnum.monthly,
|
||||
active: true,
|
||||
nextRunDate: '2026-09-01T00:00:00.000Z',
|
||||
};
|
||||
subscriptionService.upsertSubscription.mockResolvedValue(subscription);
|
||||
|
||||
await request(app.getHttpServer())
|
||||
.put('/api/v1/cashbox-export/5/subscription')
|
||||
.set('Authorization', 'Bearer user')
|
||||
.send({ recipients: ['vorstand@example.com'], interval: 'monthly', active: true })
|
||||
.expect(200)
|
||||
.expect(subscription);
|
||||
expect(subscriptionService.upsertSubscription).toHaveBeenCalledWith(5, 42, {
|
||||
recipients: ['vorstand@example.com'],
|
||||
interval: 'monthly',
|
||||
active: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user