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
@@ -13,7 +13,7 @@ import type {
} from '@mento/shared';
import { PrismaService } from '../prisma/prisma.service';
import { NotificationsService } from '../notifications/notifications.service';
import { SmsService } from '../common/sms.service';
import { SmsGatewayService } from '../sms-billing/sms-gateway.service';
import ExcelJS from 'exceljs';
import type { Actor } from '../common/record-scope';
@@ -47,7 +47,7 @@ export class TreasuryReceivablesService {
constructor(
private readonly prisma: PrismaService,
private readonly notifications: NotificationsService,
private readonly sms: SmsService,
private readonly sms: SmsGatewayService,
) {}
async list(actor: Actor): Promise<FinancialReceivableDto[]> {
@@ -306,8 +306,15 @@ export class TreasuryReceivablesService {
where: { id: admin.userId },
select: { mobile: true },
});
if (user?.mobile && this.sms.isConfigured()) {
await this.sms.sendSmsDetailed(user.mobile, `${title}: ${body}`).catch(() => undefined);
if (user?.mobile) {
await this.sms
.send({
organizationId: row.receivable.organizationId,
phone: user.mobile,
text: `${title}: ${body}`,
source: 'treasury_reminder',
})
.catch(() => undefined);
}
}
await this.prisma.financialInstallment.update({