From aa2bbe3caf272d7826e62de9f5badec57653af02 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Thu, 9 Jul 2026 20:03:57 +0330 Subject: [PATCH] send sms for user --- src/customers/customers.controller.ts | 14 +++++++++ src/customers/customers.module.ts | 9 ++++-- src/customers/customers.service.ts | 33 ++++++++++++++++++++++ src/customers/dto/send-customer-sms.dto.ts | 8 ++++++ 4 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 src/customers/dto/send-customer-sms.dto.ts diff --git a/src/customers/customers.controller.ts b/src/customers/customers.controller.ts index 36ce0db..ddcf977 100644 --- a/src/customers/customers.controller.ts +++ b/src/customers/customers.controller.ts @@ -29,6 +29,8 @@ import { SalonCustomerDetailDto, SalonCustomerListResponseDto, } from './dto/salon-customer-response.dto'; +import { SendCustomerSmsDto } from './dto/send-customer-sms.dto'; +import { SentMessage } from '../sent-messages/entities/sent-message.entity'; import { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup'; import { ApiStandardController, @@ -78,6 +80,18 @@ export class CustomersController { return this.customersService.findOneForSalon(id, user); } + @Roles(UserRole.SALON) + @Permissions(PermissionCode.CUSTOMERS_WRITE) + @ApiStandardOkResponse(SentMessage) + @Post('salon/:id/send-sms') + sendSmsToCustomer( + @Param('id', ParseUUIDPipe) id: string, + @Body() dto: SendCustomerSmsDto, + @CurrentUser() user: AuthUser, + ) { + return this.customersService.sendSmsToCustomer(id, dto, user); + } + @Roles(UserRole.ADMIN) @Permissions(PermissionCode.CUSTOMERS_READ) @ApiStandardOkResponse(Customer, { isArray: true }) diff --git a/src/customers/customers.module.ts b/src/customers/customers.module.ts index 5b00340..f6481fc 100644 --- a/src/customers/customers.module.ts +++ b/src/customers/customers.module.ts @@ -1,9 +1,12 @@ -import { Module } from '@nestjs/common'; +import { Module, forwardRef } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { AuthGuardsModule } from '../auth/auth-guards.module'; import { AuthorizationModule } from '../authorization/authorization.module'; import { Reserve } from '../reserves/entities/reserve.entity'; import { Salon } from '../salons/entities/salon.entity'; +import { SentMessage } from '../sent-messages/entities/sent-message.entity'; +import { SmsModule } from '../sms/sms.module'; +import { SubscriptionsModule } from '../subscriptions/subscriptions.module'; import { UsersModule } from '../users/users.module'; import { CustomersController } from './customers.controller'; import { CustomersService } from './customers.service'; @@ -12,10 +15,12 @@ import { SalonCustomer } from './entities/salon-customer.entity'; @Module({ imports: [ - TypeOrmModule.forFeature([Customer, SalonCustomer, Salon, Reserve]), + TypeOrmModule.forFeature([Customer, SalonCustomer, Salon, Reserve, SentMessage]), UsersModule, AuthorizationModule, AuthGuardsModule, + SmsModule, + forwardRef(() => SubscriptionsModule), ], controllers: [CustomersController], providers: [CustomersService], diff --git a/src/customers/customers.service.ts b/src/customers/customers.service.ts index aba4998..87007d6 100644 --- a/src/customers/customers.service.ts +++ b/src/customers/customers.service.ts @@ -10,11 +10,16 @@ import { AuthUser } from '../auth/interfaces/auth-user.interface'; import { Reserve } from '../reserves/entities/reserve.entity'; import { ReserveStatus } from '../reserves/enums/reserve-status.enum'; import { Salon } from '../salons/entities/salon.entity'; +import { SentMessage } from '../sent-messages/entities/sent-message.entity'; +import { SentMessageStatus } from '../sent-messages/enums/sent-message-status.enum'; +import { SmsService } from '../sms/sms.service'; +import { SalonSubscriptionsService } from '../subscriptions/salon-subscriptions.service'; import { UserRole } from '../users/enums/user-role.enum'; import { UsersService } from '../users/users.service'; import { CreateCustomerDto } from './dto/create-customer.dto'; import { CreateSalonCustomerDto } from './dto/salon-customer.dto'; import { FindSalonCustomersQueryDto } from './dto/salon-customer.dto'; +import { SendCustomerSmsDto } from './dto/send-customer-sms.dto'; import { SalonCustomerDetailDto, SalonCustomerListResponseDto, @@ -43,8 +48,12 @@ export class CustomersService { private readonly salonsRepository: Repository, @InjectRepository(Reserve) private readonly reservesRepository: Repository, + @InjectRepository(SentMessage) + private readonly sentMessagesRepository: Repository, private readonly usersService: UsersService, private readonly customerPolicy: CustomerPolicy, + private readonly smsService: SmsService, + private readonly salonSubscriptionsService: SalonSubscriptionsService, ) {} async create(createCustomerDto: CreateCustomerDto): Promise { @@ -107,6 +116,30 @@ export class CustomersService { return this.buildSalonCustomerDetail(customer, salon.id); } + async sendSmsToCustomer( + id: string, + dto: SendCustomerSmsDto, + user: AuthUser, + ): Promise { + const salon = await this.resolveSalonForUser(user); + const detail = await this.findOneForSalon(id, user); + + await this.salonSubscriptionsService.consumeSms(salon.id, 1); + + const sent = await this.smsService.sendSms(detail.mobile, dto.body); + const status = sent ? SentMessageStatus.SENT : SentMessageStatus.FAILED; + + return this.sentMessagesRepository.save( + this.sentMessagesRepository.create({ + salonId: salon.id, + customerId: id, + mobile: detail.mobile, + body: dto.body, + status, + }), + ); + } + async createForSalon( dto: CreateSalonCustomerDto, user: AuthUser, diff --git a/src/customers/dto/send-customer-sms.dto.ts b/src/customers/dto/send-customer-sms.dto.ts new file mode 100644 index 0000000..d1d42be --- /dev/null +++ b/src/customers/dto/send-customer-sms.dto.ts @@ -0,0 +1,8 @@ +import { IsNotEmpty, IsString, MaxLength } from 'class-validator'; + +export class SendCustomerSmsDto { + @IsString() + @IsNotEmpty() + @MaxLength(1000) + body: string; +}