invoice event
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
export class InvoiceCreatedEvent {
|
||||
constructor(
|
||||
public readonly invoiceId: string,
|
||||
public readonly invoiceNumber: string,
|
||||
public readonly total: number,
|
||||
public readonly userId: string,
|
||||
) {}
|
||||
}
|
||||
|
||||
// export class OrderStatusChangedEvent {
|
||||
// constructor(
|
||||
// public readonly orderId: string,
|
||||
// public readonly userId: string,
|
||||
// public readonly orderNumber: string,
|
||||
// public readonly: string,
|
||||
// public readonly previousStatus: OrderStatusEnum,
|
||||
// public readonly newStatus: OrderStatusEnum,
|
||||
// ) { }
|
||||
// }
|
||||
@@ -6,9 +6,11 @@ import { Invoice } from './entities/invoice.entity';
|
||||
import { InvoiceItem } from './entities/invoice-item.entity';
|
||||
import { ProductModule } from '../product/product.module';
|
||||
import { InvoiceRepository } from './repositories/invoice.repository';
|
||||
import { InvoiceListeners } from './listeners/invoice.listeners';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { RolesModule } from '../roles/roles.module';
|
||||
import { AuthModule } from '../auth/auth.module';
|
||||
import { NotificationsModule } from '../notification/notifications.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -16,10 +18,11 @@ import { AuthModule } from '../auth/auth.module';
|
||||
ProductModule,
|
||||
RolesModule,
|
||||
JwtModule,
|
||||
AuthModule
|
||||
AuthModule,
|
||||
NotificationsModule,
|
||||
],
|
||||
controllers: [InvoiceController],
|
||||
providers: [InvoiceService, InvoiceRepository],
|
||||
providers: [InvoiceService, InvoiceRepository, InvoiceListeners],
|
||||
exports: [InvoiceService, InvoiceRepository],
|
||||
})
|
||||
export class InvoiceModule { }
|
||||
export class InvoiceModule {}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
|
||||
import { EntityManager } from '@mikro-orm/postgresql';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { CreateInvoiceDto } from './dto/create-invoice.dto';
|
||||
import { UpdateInvoiceDto } from './dto/update-invoice.dto';
|
||||
import { FindInvoicesDto } from './dto/find-invoices.dto';
|
||||
@@ -9,6 +10,7 @@ import { Request } from '../request/entities/request.entity';
|
||||
import { User } from '../user/entities/user.entity';
|
||||
import { ProductService } from '../product/providers/product.service';
|
||||
import { InvoiceRepository } from './repositories/invoice.repository';
|
||||
import { InvoiceCreatedEvent } from './events/invoice.events';
|
||||
|
||||
const TAX_RATE = 0.1;
|
||||
|
||||
@@ -18,7 +20,8 @@ export class InvoiceService {
|
||||
private readonly em: EntityManager,
|
||||
private readonly productService: ProductService,
|
||||
private readonly invoiceRepository: InvoiceRepository,
|
||||
) { }
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
) {}
|
||||
|
||||
|
||||
async create(dto: CreateInvoiceDto) {
|
||||
@@ -49,7 +52,7 @@ export class InvoiceService {
|
||||
|
||||
const discount = dto.items.reduce((acc, item) => acc + (item.discount ?? 0), 0);
|
||||
|
||||
return this.em.transactional(async (em) => {
|
||||
const invoice = await this.em.transactional(async (em) => {
|
||||
const invoice = em.create(Invoice, {
|
||||
user,
|
||||
...(request && { request }),
|
||||
@@ -98,6 +101,18 @@ export class InvoiceService {
|
||||
await em.flush();
|
||||
return invoice;
|
||||
});
|
||||
|
||||
this.eventEmitter.emit(
|
||||
InvoiceCreatedEvent.name,
|
||||
new InvoiceCreatedEvent(
|
||||
invoice.id,
|
||||
String(invoice.invoiceNumber),
|
||||
invoice.total!,
|
||||
user.id,
|
||||
),
|
||||
);
|
||||
|
||||
return invoice;
|
||||
}
|
||||
|
||||
findAll(userId: string, dto: FindInvoicesDto) {
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { NotificationQueueService } from 'src/modules/notification/services/notification-queue.service';
|
||||
import { InvoiceCreatedEvent } from '../events/invoice.events';
|
||||
|
||||
@Injectable()
|
||||
export class InvoiceListeners {
|
||||
private readonly logger = new Logger(InvoiceListeners.name);
|
||||
private invoiceCreatedSmsTemplateId: string;
|
||||
|
||||
constructor(
|
||||
private readonly notificationQueueService: NotificationQueueService,
|
||||
private readonly configService: ConfigService,
|
||||
) {
|
||||
this.invoiceCreatedSmsTemplateId =
|
||||
this.configService.get<string>('SMS_PATTERN_INVOICE_CREATED') ?? 'invoice-created';
|
||||
}
|
||||
|
||||
@OnEvent(InvoiceCreatedEvent.name)
|
||||
async handleInvoiceCreated(event: InvoiceCreatedEvent) {
|
||||
try {
|
||||
this.logger.log(
|
||||
`Invoice created event received: ${event.invoiceId} for user: ${event.userId}, invoice number: ${event.invoiceNumber}`,
|
||||
);
|
||||
|
||||
await this.notificationQueueService.addSmsNotification({
|
||||
recipient: { userId: event.userId },
|
||||
templateId: this.invoiceCreatedSmsTemplateId,
|
||||
parameters: {
|
||||
invoiceNumber: event.invoiceNumber,
|
||||
total: event.total.toString(),
|
||||
},
|
||||
});
|
||||
|
||||
this.logger.log(`Invoice created notification queued for user ${event.userId}`);
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Failed to send notification for invoice created event: ${event.invoiceId}`,
|
||||
error instanceof Error ? error.stack : String(error),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,6 +64,15 @@ export class LearningController {
|
||||
|
||||
// ----------------- Admin routes -----------------
|
||||
|
||||
@Get('admin/learnings')
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@Permissions(PermissionEnum.MANAGE_LEARNINGS)
|
||||
@ApiOperation({ summary: 'Find all learnings videos as admin' })
|
||||
findAllLearningsAsAdmin() {
|
||||
return this.learningService.findLearningsVideos();
|
||||
}
|
||||
|
||||
|
||||
@Post('admin/learnings')
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@Permissions(PermissionEnum.MANAGE_LEARNINGS)
|
||||
@@ -96,6 +105,14 @@ export class LearningController {
|
||||
return this.learningService.createLearningCategory(createDto);
|
||||
}
|
||||
|
||||
@Get('admin/learnings/category')
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@Permissions(PermissionEnum.MANAGE_LEARNINGS)
|
||||
@ApiOperation({ summary: 'Get all learning categories' })
|
||||
getCategories() {
|
||||
return this.learningService.findCategories()
|
||||
}
|
||||
|
||||
@Patch('admin/learnings/category/:id')
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@Permissions(PermissionEnum.MANAGE_LEARNINGS)
|
||||
|
||||
@@ -60,7 +60,7 @@ export class LearningService {
|
||||
}
|
||||
|
||||
async findLearningsVideos() {
|
||||
const learnings = await this.learningRepository.findAll();
|
||||
const learnings = await this.learningRepository.findAll({populate: ['category']});
|
||||
|
||||
return { learnings };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user