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
@@ -2,7 +2,7 @@ import { Injectable, Logger } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';
import { NotificationsService } from '../notifications/notifications.service';
import { PrismaService } from '../prisma/prisma.service';
import { SmsService } from '../common/sms.service';
import { SmsGatewayService } from '../sms-billing/sms-gateway.service';
import {
CHEQUE_REMINDER_DAYS,
isDueInDays,
@@ -18,7 +18,7 @@ export class ChequeRemindersService {
constructor(
private readonly prisma: PrismaService,
private readonly notifications: NotificationsService,
private readonly sms: SmsService,
private readonly sms: SmsGatewayService,
) {}
@Cron('0 8 * * *', { timeZone: 'Asia/Tehran' })
@@ -134,20 +134,27 @@ export class ChequeRemindersService {
dedupe: true,
});
if (user.mobile) {
await this.sms.sendSmsDetailed(user.mobile, staffText);
await this.sms.send({
organizationId: row.organizationId,
phone: user.mobile,
text: staffText,
source: 'cheque_reminder',
});
}
}
if (incoming && row.person?.mobile) {
await this.sms.sendSmsDetailed(
row.person.mobile,
personIncomingSms({
await this.sms.send({
organizationId: row.organizationId,
phone: row.person.mobile,
text: personIncomingSms({
number: row.number,
amount,
currency: row.currency,
dueDate: row.dueDate,
}),
);
source: 'cheque_reminder',
});
}
}
}