79 lines
2.4 KiB
TypeScript
79 lines
2.4 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { DataSource, Repository } from 'typeorm';
|
|
import { Invoice, InvoiceStatus } from '../../domain/entities/invoice.entity';
|
|
import { InvoiceItem } from '../../domain/entities/invoice-item.entity';
|
|
|
|
@Injectable()
|
|
export class InvoiceRepository {
|
|
private readonly repo: Repository<Invoice>;
|
|
private readonly itemRepo: Repository<InvoiceItem>;
|
|
|
|
constructor(private readonly dataSource: DataSource) {
|
|
this.repo = this.dataSource.getRepository(Invoice);
|
|
this.itemRepo = this.dataSource.getRepository(InvoiceItem);
|
|
}
|
|
|
|
async findByTenantId(tenantId: string, limit = 20, offset = 0): Promise<[Invoice[], number]> {
|
|
return this.repo.findAndCount({
|
|
where: { tenantId },
|
|
order: { createdAt: 'DESC' },
|
|
take: limit,
|
|
skip: offset,
|
|
});
|
|
}
|
|
|
|
async findById(id: string): Promise<Invoice | null> {
|
|
return this.repo.findOne({ where: { id }, relations: ['items'] });
|
|
}
|
|
|
|
async findByInvoiceNumber(invoiceNumber: string): Promise<Invoice | null> {
|
|
return this.repo.findOne({ where: { invoiceNumber } });
|
|
}
|
|
|
|
async findUnpaidByTenantId(tenantId: string): Promise<Invoice[]> {
|
|
return this.repo.find({
|
|
where: [
|
|
{ tenantId, status: InvoiceStatus.OPEN },
|
|
{ tenantId, status: InvoiceStatus.PAST_DUE },
|
|
],
|
|
});
|
|
}
|
|
|
|
async getNextInvoiceNumber(): Promise<string> {
|
|
const result = await this.dataSource.query(
|
|
`SELECT nextval('billing_invoice_number_seq') AS seq`,
|
|
);
|
|
const seq = result[0]?.seq ?? Date.now();
|
|
const year = new Date().getFullYear();
|
|
return `INV-${year}-${String(seq).padStart(6, '0')}`;
|
|
}
|
|
|
|
async save(invoice: Invoice): Promise<Invoice> {
|
|
return this.repo.save(invoice);
|
|
}
|
|
|
|
async saveItems(items: InvoiceItem[]): Promise<InvoiceItem[]> {
|
|
return this.itemRepo.save(items);
|
|
}
|
|
|
|
async saveWithItems(invoice: Invoice, items: InvoiceItem[]): Promise<Invoice> {
|
|
const runner = this.dataSource.createQueryRunner();
|
|
await runner.connect();
|
|
await runner.startTransaction();
|
|
try {
|
|
const savedInvoice = await runner.manager.save(Invoice, invoice);
|
|
for (const item of items) {
|
|
item.invoiceId = savedInvoice.id;
|
|
}
|
|
await runner.manager.save(InvoiceItem, items);
|
|
await runner.commitTransaction();
|
|
return savedInvoice;
|
|
} catch (err) {
|
|
await runner.rollbackTransaction();
|
|
throw err;
|
|
} finally {
|
|
await runner.release();
|
|
}
|
|
}
|
|
}
|