Add invoice PDF download and unified payment.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
keyhan
2026-05-18 22:01:44 +03:30
parent 8b197e69bc
commit d5e6ab0f68
4 changed files with 191 additions and 72 deletions
+31 -18
View File
@@ -9,11 +9,13 @@ import {
Query,
UseGuards,
Request,
Res,
BadRequestException,
Inject,
forwardRef,
ForbiddenException,
} from '@nestjs/common';
import { Response } from 'express';
import { AuthGuard } from '@nestjs/passport';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { BillingService } from './billing.service';
@@ -162,30 +164,26 @@ export class BillingController {
});
}
@Get('invoices/:id/pdf')
@ApiOperation({ summary: 'Download invoice as PDF' })
async downloadInvoicePdf(
@Request() req: any,
@Param('id') id: string,
@Res() res: Response,
) {
const invoice = await this.billingService.getInvoiceForUser(id, req.user);
const pdf = this.billingService.generateInvoicePdf(invoice);
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition', `attachment; filename="${invoice.invoiceNumber}.pdf"`);
res.send(pdf);
}
@Get('invoices/:id')
@ApiOperation({ summary: 'Get one invoice with line items and transactions' })
async getInvoice(@Request() req: any, @Param('id') id: string) {
return this.billingService.getInvoiceForUser(id, req.user);
}
@Post('invoices/:id/pay/wallet')
@ApiOperation({ summary: 'Pay invoice from wallet balance' })
async payInvoiceWallet(@Request() req: any, @Param('id') id: string) {
const result = await this.billingService.payInvoiceWithWallet(id, req.user);
const effect = await this.completePaidInvoiceEffect(result.invoice);
return { ...result, effect };
}
@Post('invoices/:id/pay/gateway')
@ApiOperation({ summary: 'Initiate direct gateway payment for invoice' })
async initiateInvoiceGateway(
@Request() req: any,
@Param('id') id: string,
@Body() dto: InitiateInvoicePaymentDto,
) {
return this.billingService.initiateInvoiceGatewayPayment(id, req.user, dto.callbackUrl);
}
@Post('invoices/:id/pay/mixed')
@ApiOperation({ summary: 'Pay invoice with wallet first, then gateway for the remaining amount' })
async initiateInvoiceMixed(
@@ -366,6 +364,21 @@ export class BillingController {
return this.billingService.getInvoiceForUser(id, req.user);
}
@Get('admin/invoices/:id/pdf')
@Roles(UserRole.ADMIN)
@ApiOperation({ summary: 'Download invoice PDF (Admin)' })
async downloadAdminInvoicePdf(
@Request() req: any,
@Param('id') id: string,
@Res() res: Response,
) {
const invoice = await this.billingService.getInvoiceForUser(id, req.user);
const pdf = this.billingService.generateInvoicePdf(invoice);
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition', `attachment; filename="${invoice.invoiceNumber}.pdf"`);
res.send(pdf);
}
@Patch('admin/invoices/:id/status')
@Roles(UserRole.ADMIN)
@ApiOperation({ summary: 'Update invoice status with reason (Admin)' })