feat: add per-org SMS wallet with adm panel and header credit

Bill all platform SMS (including OTP), allow negative balance with manual/auto cutoffs, and support own-panel bypass without wallet debit.
This commit is contained in:
2026-10-19 15:55:48 +03:30
parent f15ebb72ea
commit f5d68d83fc
42 changed files with 2073 additions and 121 deletions
+1 -2
View File
@@ -1,9 +1,8 @@
import { Module } from '@nestjs/common';
import { SmsService } from '../common/sms.service';
import { AttendanceService } from './attendance.service';
@Module({
providers: [AttendanceService, SmsService],
providers: [AttendanceService],
exports: [AttendanceService],
})
export class AttendanceModule {}
@@ -1,8 +1,8 @@
import { Injectable, Logger, UnauthorizedException } from '@nestjs/common';
import { Prisma } from '@prisma/client';
import type { Actor } from '../common/record-scope';
import { SmsService } from '../common/sms.service';
import { PrismaService } from '../prisma/prisma.service';
import { SmsGatewayService } from '../sms-billing/sms-gateway.service';
import {
loggedInAfterCutoff,
tehranClock,
@@ -29,7 +29,7 @@ export class AttendanceService {
constructor(
private readonly prisma: PrismaService,
private readonly sms: SmsService,
private readonly sms: SmsGatewayService,
) {}
async recordLogin(organizationId: string, userId: string, role: string, at = new Date()) {
@@ -185,6 +185,11 @@ export class AttendanceService {
: input.kind === 'forced_logout'
? `${name} در ساعت تعیین‌شده از منتکت خارج شد. ساعت ${clock}`
: `${name} از منتکت خارج شد. ساعت ${clock}`;
await this.sms.sendSmsDetailed(owner.user.mobile, text);
await this.sms.send({
organizationId: input.organizationId,
phone: owner.user.mobile,
text,
source: 'attendance',
});
}
}