- Modified TypeScript configuration to disable strict mode and allow importing TypeScript extensions. - Updated Prisma schema to enhance the User model with a new debtAccounts field and refined asset/liability types. - Adjusted environment variable parsing for PORT to use coercion for better type handling. - Refactored various controllers and repositories to utilize type imports for better clarity and maintainability. - Enhanced service layers with new methods for retrieving assets by type and calculating invoice statistics. - Introduced new types for invoice statuses and asset types to ensure consistency across the application.
138 lines
3.7 KiB
TypeScript
138 lines
3.7 KiB
TypeScript
import type {FastifyRequest, FastifyReply} from 'fastify';
|
|
import {InvoiceService} from '../services/InvoiceService';
|
|
import {getUserId} from '../middleware/auth';
|
|
import {z} from 'zod';
|
|
|
|
const lineItemSchema = z.object({
|
|
description: z.string().min(1),
|
|
quantity: z.number().min(1),
|
|
unitPrice: z.number().min(0),
|
|
amount: z.number().min(0),
|
|
});
|
|
|
|
const createInvoiceSchema = z.object({
|
|
clientId: z.string().uuid(),
|
|
issueDate: z.string().transform(str => new Date(str)),
|
|
dueDate: z.string().transform(str => new Date(str)),
|
|
lineItems: z.array(lineItemSchema).min(1),
|
|
notes: z.string().optional(),
|
|
terms: z.string().optional(),
|
|
});
|
|
|
|
const updateInvoiceSchema = z.object({
|
|
issueDate: z.string().transform(str => new Date(str)).optional(),
|
|
dueDate: z.string().transform(str => new Date(str)).optional(),
|
|
lineItems: z.array(lineItemSchema).min(1).optional(),
|
|
notes: z.string().optional(),
|
|
terms: z.string().optional(),
|
|
});
|
|
|
|
const updateStatusSchema = z.object({
|
|
status: z.enum(['DRAFT', 'SENT', 'PAID', 'OVERDUE', 'CANCELLED']),
|
|
});
|
|
|
|
/**
|
|
* Controller for Invoice endpoints
|
|
* Implements Single Responsibility Principle - handles only HTTP layer
|
|
*/
|
|
export class InvoiceController {
|
|
constructor(private invoiceService: InvoiceService) {}
|
|
|
|
/**
|
|
* Create a new invoice
|
|
*/
|
|
async create(request: FastifyRequest, reply: FastifyReply) {
|
|
const userId = getUserId(request);
|
|
const data = createInvoiceSchema.parse(request.body);
|
|
|
|
const invoice = await this.invoiceService.create(userId, data);
|
|
|
|
return reply.status(201).send({invoice});
|
|
}
|
|
|
|
/**
|
|
* Get all invoices for the authenticated user
|
|
*/
|
|
async getAll(request: FastifyRequest, reply: FastifyReply) {
|
|
const userId = getUserId(request);
|
|
const {clientId, status} = request.query as {clientId?: string; status?: string};
|
|
|
|
const invoices = await this.invoiceService.getAllByUser(userId, {
|
|
clientId,
|
|
status,
|
|
});
|
|
|
|
return reply.send({invoices});
|
|
}
|
|
|
|
/**
|
|
* Get a single invoice by ID
|
|
*/
|
|
async getOne(request: FastifyRequest, reply: FastifyReply) {
|
|
const userId = getUserId(request);
|
|
const {id} = request.params as {id: string};
|
|
|
|
const invoice = await this.invoiceService.getById(id, userId);
|
|
|
|
return reply.send({invoice});
|
|
}
|
|
|
|
/**
|
|
* Update an invoice
|
|
*/
|
|
async update(request: FastifyRequest, reply: FastifyReply) {
|
|
const userId = getUserId(request);
|
|
const {id} = request.params as {id: string};
|
|
const data = updateInvoiceSchema.parse(request.body);
|
|
|
|
const invoice = await this.invoiceService.update(id, userId, data);
|
|
|
|
return reply.send({invoice});
|
|
}
|
|
|
|
/**
|
|
* Update invoice status
|
|
*/
|
|
async updateStatus(request: FastifyRequest, reply: FastifyReply) {
|
|
const userId = getUserId(request);
|
|
const {id} = request.params as {id: string};
|
|
const {status} = updateStatusSchema.parse(request.body);
|
|
|
|
const invoice = await this.invoiceService.updateStatus(id, userId, status);
|
|
|
|
return reply.send({invoice});
|
|
}
|
|
|
|
/**
|
|
* Delete an invoice
|
|
*/
|
|
async delete(request: FastifyRequest, reply: FastifyReply) {
|
|
const userId = getUserId(request);
|
|
const {id} = request.params as {id: string};
|
|
|
|
await this.invoiceService.delete(id, userId);
|
|
|
|
return reply.status(204).send();
|
|
}
|
|
|
|
/**
|
|
* Get invoice statistics
|
|
*/
|
|
async getStats(request: FastifyRequest, reply: FastifyReply) {
|
|
const userId = getUserId(request);
|
|
const stats = await this.invoiceService.getStats(userId);
|
|
|
|
return reply.send({stats});
|
|
}
|
|
|
|
/**
|
|
* Get overdue invoices
|
|
*/
|
|
async getOverdue(request: FastifyRequest, reply: FastifyReply) {
|
|
const userId = getUserId(request);
|
|
const overdueInvoices = await this.invoiceService.getOverdueInvoices(userId);
|
|
|
|
return reply.send({invoices: overdueInvoices});
|
|
}
|
|
}
|