Add SMS templates, prepaid IRT billing, and advertising shortcode 9000590009.
Charge ceil(len/64)*400 IRT per recipient across OTP, customer, and partner SMS; seed new businesses with 500k IRT; default partner sends to the advertising line. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
4623061a4f
commit
4a1d60dbef
+18
-11
@@ -28,6 +28,7 @@ import { UpdateProfileDto } from './dto/update-profile.dto';
|
||||
import { PermissionsService } from './permissions.service';
|
||||
import { parseUserProfile } from './profile.util';
|
||||
import { SmsService } from './sms.service';
|
||||
import { SmsBillingService } from './sms-billing.service';
|
||||
|
||||
const OTP_TTL_SECONDS = 300;
|
||||
/** Pending cross-site password change (longer than OTP so resend still works). */
|
||||
@@ -44,6 +45,7 @@ export class AuthService {
|
||||
private readonly config: ConfigService,
|
||||
private readonly redis: RedisService,
|
||||
private readonly sms: SmsService,
|
||||
private readonly smsBilling: SmsBillingService,
|
||||
private readonly tenant: TenantService,
|
||||
private readonly permissions: PermissionsService,
|
||||
) {}
|
||||
@@ -403,7 +405,7 @@ export class AuthService {
|
||||
return { message: 'Password changed successfully' };
|
||||
}
|
||||
|
||||
async sendOtp(cellNumber: string, domain?: string) {
|
||||
async sendOtp(cellNumber: string, domain: string) {
|
||||
if (!this.sms.isEnabled()) {
|
||||
return {
|
||||
enabled: false,
|
||||
@@ -420,24 +422,29 @@ export class AuthService {
|
||||
throw new UnauthorizedException('Cell number is not registered');
|
||||
}
|
||||
|
||||
let businessNameFa: string | undefined;
|
||||
const host = domain?.trim();
|
||||
if (host) {
|
||||
try {
|
||||
const business = await this.tenant.resolveBusinessByDomain(host);
|
||||
businessNameFa =
|
||||
business.nameFa?.trim() || business.name?.trim() || undefined;
|
||||
} catch {
|
||||
// Domain may be unknown — still send OTP without branding suffix
|
||||
}
|
||||
if (!host) {
|
||||
throw new BadRequestException(
|
||||
'Domain is required to send SMS (prepaid balance is billed per business).',
|
||||
);
|
||||
}
|
||||
|
||||
const business = await this.tenant.resolveBusinessByDomain(host);
|
||||
const businessNameFa =
|
||||
business.nameFa?.trim() || business.name?.trim() || undefined;
|
||||
const code = this.generateOtpCode();
|
||||
const brand = businessNameFa?.trim();
|
||||
const message = brand
|
||||
? `کد تایید شما: ${code}\n${brand}`
|
||||
: `کد تایید شما: ${code}`;
|
||||
|
||||
const charged = await this.smsBilling.charge(business.id, message);
|
||||
await this.redis.setOtp(cellNumber, code, OTP_TTL_SECONDS);
|
||||
|
||||
try {
|
||||
await this.sms.sendVerificationCode(cellNumber, code, businessNameFa);
|
||||
await this.sms.sendMessage(cellNumber, message);
|
||||
} catch (err) {
|
||||
await this.smsBilling.refund(business.id, charged);
|
||||
if (err instanceof HttpException) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user