send sms for user

This commit is contained in:
2026-07-09 20:03:57 +03:30
parent ffb95149cf
commit aa2bbe3caf
4 changed files with 62 additions and 2 deletions
+14
View File
@@ -29,6 +29,8 @@ import {
SalonCustomerDetailDto, SalonCustomerDetailDto,
SalonCustomerListResponseDto, SalonCustomerListResponseDto,
} from './dto/salon-customer-response.dto'; } 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 { SWAGGER_JWT_AUTH } from '../swagger/swagger.setup';
import { import {
ApiStandardController, ApiStandardController,
@@ -78,6 +80,18 @@ export class CustomersController {
return this.customersService.findOneForSalon(id, user); 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) @Roles(UserRole.ADMIN)
@Permissions(PermissionCode.CUSTOMERS_READ) @Permissions(PermissionCode.CUSTOMERS_READ)
@ApiStandardOkResponse(Customer, { isArray: true }) @ApiStandardOkResponse(Customer, { isArray: true })
+7 -2
View File
@@ -1,9 +1,12 @@
import { Module } from '@nestjs/common'; import { Module, forwardRef } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthGuardsModule } from '../auth/auth-guards.module'; import { AuthGuardsModule } from '../auth/auth-guards.module';
import { AuthorizationModule } from '../authorization/authorization.module'; import { AuthorizationModule } from '../authorization/authorization.module';
import { Reserve } from '../reserves/entities/reserve.entity'; import { Reserve } from '../reserves/entities/reserve.entity';
import { Salon } from '../salons/entities/salon.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 { UsersModule } from '../users/users.module';
import { CustomersController } from './customers.controller'; import { CustomersController } from './customers.controller';
import { CustomersService } from './customers.service'; import { CustomersService } from './customers.service';
@@ -12,10 +15,12 @@ import { SalonCustomer } from './entities/salon-customer.entity';
@Module({ @Module({
imports: [ imports: [
TypeOrmModule.forFeature([Customer, SalonCustomer, Salon, Reserve]), TypeOrmModule.forFeature([Customer, SalonCustomer, Salon, Reserve, SentMessage]),
UsersModule, UsersModule,
AuthorizationModule, AuthorizationModule,
AuthGuardsModule, AuthGuardsModule,
SmsModule,
forwardRef(() => SubscriptionsModule),
], ],
controllers: [CustomersController], controllers: [CustomersController],
providers: [CustomersService], providers: [CustomersService],
+33
View File
@@ -10,11 +10,16 @@ import { AuthUser } from '../auth/interfaces/auth-user.interface';
import { Reserve } from '../reserves/entities/reserve.entity'; import { Reserve } from '../reserves/entities/reserve.entity';
import { ReserveStatus } from '../reserves/enums/reserve-status.enum'; import { ReserveStatus } from '../reserves/enums/reserve-status.enum';
import { Salon } from '../salons/entities/salon.entity'; 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 { UserRole } from '../users/enums/user-role.enum';
import { UsersService } from '../users/users.service'; import { UsersService } from '../users/users.service';
import { CreateCustomerDto } from './dto/create-customer.dto'; import { CreateCustomerDto } from './dto/create-customer.dto';
import { CreateSalonCustomerDto } from './dto/salon-customer.dto'; import { CreateSalonCustomerDto } from './dto/salon-customer.dto';
import { FindSalonCustomersQueryDto } from './dto/salon-customer.dto'; import { FindSalonCustomersQueryDto } from './dto/salon-customer.dto';
import { SendCustomerSmsDto } from './dto/send-customer-sms.dto';
import { import {
SalonCustomerDetailDto, SalonCustomerDetailDto,
SalonCustomerListResponseDto, SalonCustomerListResponseDto,
@@ -43,8 +48,12 @@ export class CustomersService {
private readonly salonsRepository: Repository<Salon>, private readonly salonsRepository: Repository<Salon>,
@InjectRepository(Reserve) @InjectRepository(Reserve)
private readonly reservesRepository: Repository<Reserve>, private readonly reservesRepository: Repository<Reserve>,
@InjectRepository(SentMessage)
private readonly sentMessagesRepository: Repository<SentMessage>,
private readonly usersService: UsersService, private readonly usersService: UsersService,
private readonly customerPolicy: CustomerPolicy, private readonly customerPolicy: CustomerPolicy,
private readonly smsService: SmsService,
private readonly salonSubscriptionsService: SalonSubscriptionsService,
) {} ) {}
async create(createCustomerDto: CreateCustomerDto): Promise<Customer> { async create(createCustomerDto: CreateCustomerDto): Promise<Customer> {
@@ -107,6 +116,30 @@ export class CustomersService {
return this.buildSalonCustomerDetail(customer, salon.id); return this.buildSalonCustomerDetail(customer, salon.id);
} }
async sendSmsToCustomer(
id: string,
dto: SendCustomerSmsDto,
user: AuthUser,
): Promise<SentMessage> {
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( async createForSalon(
dto: CreateSalonCustomerDto, dto: CreateSalonCustomerDto,
user: AuthUser, user: AuthUser,
@@ -0,0 +1,8 @@
import { IsNotEmpty, IsString, MaxLength } from 'class-validator';
export class SendCustomerSmsDto {
@IsString()
@IsNotEmpty()
@MaxLength(1000)
body: string;
}