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
+30 -7
View File
@@ -10,8 +10,19 @@ const SMS_0098_SOAP_URL = 'https://webservice.0098sms.com/service.asmx';
export type SmsSendResult = {
ok: boolean;
transport: 'trez' | 'soap' | 'link';
blocked?: boolean;
transport: 'trez' | 'soap' | 'link' | 'none';
reason?: string;
parts?: number;
costRials?: number;
};
export type SmsTransportOverride = {
username: string;
password: string;
sender: string;
/** trez | 0098 — default 0098 for own panels */
provider?: 'trez' | '0098';
};
@Injectable()
@@ -50,17 +61,29 @@ export class SmsService {
return result.ok;
}
async sendSmsDetailed(phone: string, text: string): Promise<SmsSendResult> {
const username = this.config.get<string>('SMS_USERNAME');
const password = this.getPassword();
const sender = this.config.get<string>('SMS_SENDER');
buildOtpText(code: string): string {
const template =
this.config.get<string>('SMS_OTP_TEMPLATE')?.trim() ||
`کد ورود منتکت: {code}`;
return template.replace('{code}', code);
}
async sendSmsDetailed(
phone: string,
text: string,
override?: SmsTransportOverride,
): Promise<SmsSendResult> {
const username = override?.username || this.config.get<string>('SMS_USERNAME');
const password = override?.password || this.getPassword();
const sender = override?.sender || this.config.get<string>('SMS_SENDER');
if (!username || !password || !sender) {
return { ok: false, transport: 'trez', reason: 'SMS not configured' };
return { ok: false, transport: 'none', reason: 'SMS not configured' };
}
const to = this.normalizePhoneForSms(phone);
const provider = this.resolveProvider();
const provider =
override?.provider ?? this.resolveProvider();
if (provider === 'trez') {
return this.sendViaTrez(username, password, sender, to, text);