mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 18:48:11 +00:00
feat: add otp to contract
This commit is contained in:
@@ -19,6 +19,7 @@ import { CargoTypesService } from '../rule-engine/services/cargo-types.service';
|
||||
import { DropdownSettingsService } from '../dropdown-settings/dropdown-settings.service';
|
||||
import { FilesService } from '../files/files.service';
|
||||
import { SignaturesService } from '../signatures/signatures.service';
|
||||
import { OtpService } from '../otp/otp.service';
|
||||
import { ContractPricingService } from './contract-pricing.service';
|
||||
import { ClearanceMilestoneService } from './clearance-milestone.service';
|
||||
import { ContractsRepository } from './contracts.repository';
|
||||
@@ -63,6 +64,7 @@ export class ContractTransitionService {
|
||||
private readonly renderer: ContractRendererService,
|
||||
private readonly pdfService: ContractPdfService,
|
||||
private readonly minioService: MinioService,
|
||||
private readonly otpService: OtpService,
|
||||
) {}
|
||||
|
||||
/** Customer submits the contract for approval → SUBMITTED; freeze unit rates. */
|
||||
@@ -520,6 +522,12 @@ export class ContractTransitionService {
|
||||
if (existing) {
|
||||
throw new BadRequestException('Customer has already signed this contract');
|
||||
}
|
||||
// Sudo-mode gate: a fresh, single-use OTP (SMS'd to the customer's phone)
|
||||
// must be verified before the signature is applied.
|
||||
if (!dto.otpPhone || !dto.otp) {
|
||||
throw new BadRequestException('OTP verification is required to sign the contract');
|
||||
}
|
||||
await this.otpService.verifyOtpForAction(dto.otpPhone, dto.otp);
|
||||
await this.applySignature(contract, dto, options);
|
||||
await this.contractsRepository.update(contractId, {
|
||||
status: 'SIGNED_CUSTOMER',
|
||||
|
||||
@@ -11,6 +11,7 @@ import { RuleEngineModule } from '../rule-engine/rule-engine.module';
|
||||
import { FileUploadSettingsModule } from '../file-upload-settings/file-upload-settings.module';
|
||||
import { DropdownSettingsModule } from '../dropdown-settings/dropdown-settings.module';
|
||||
import { SignaturesModule } from '../signatures/signatures.module';
|
||||
import { OtpModule } from '../otp/otp.module';
|
||||
import { BookingsModule } from '../bookings/bookings.module';
|
||||
|
||||
import { ContractsController } from './contracts.controller';
|
||||
@@ -72,6 +73,7 @@ import { ContractDocumentViewModelBuilder } from '../../contracts/contract-docum
|
||||
FilesModule,
|
||||
MinioModule,
|
||||
SignaturesModule,
|
||||
OtpModule,
|
||||
CompaniesModule,
|
||||
// BookingsModule provides BookingsRepository/BookingPricingService used by the
|
||||
// contract PDF builders (they read a Booking today — see docs/new-doc.md §3.3).
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { IsIn, IsOptional, IsString, MinLength } from 'class-validator';
|
||||
import { IsIn, IsOptional, IsString, Matches, MinLength } from 'class-validator';
|
||||
|
||||
export class SignContractDto {
|
||||
@ApiProperty({ enum: ['CUSTOMER', 'STAFF', 'DIRECTOR', 'CEO'] })
|
||||
@@ -26,4 +26,19 @@ export class SignContractDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
consentText?: string;
|
||||
|
||||
// Sudo-mode OTP challenge. Required when role=CUSTOMER: a fresh 6-digit code
|
||||
// SMS'd to the signer's phone, verified server-side before the signature is
|
||||
// applied. `otpPhone` is the number the code was sent to (the signed-in
|
||||
// customer's registered phone).
|
||||
@ApiPropertyOptional({ description: '6-digit OTP; required when role=CUSTOMER' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@Matches(/^\d{6}$/, { message: 'otp must be 6 digits' })
|
||||
otp?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Phone the OTP was sent to; required when role=CUSTOMER' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
otpPhone?: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user