chore: first commit
This commit is contained in:
Executable
+2
@@ -0,0 +1,2 @@
|
||||
export const SMS_CONFIG = "SMS_CONFIG";
|
||||
export const S3_CONFIG = "S3_CONFIG";
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
export interface IFile {
|
||||
fieldname: string;
|
||||
originalname: string;
|
||||
encoding: string;
|
||||
mimetype: string;
|
||||
buffer: Buffer;
|
||||
size: number;
|
||||
}
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
export type OtpCacheKeyType = "LOGIN" | "REGISTER" | "FORGOT_PASSWORD" | "INVOICE_VERIFY";
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
export interface IParameterArray {
|
||||
name: TemplateParams;
|
||||
value: string;
|
||||
}
|
||||
export interface ISmsResponse {
|
||||
status: number;
|
||||
message: string;
|
||||
}
|
||||
//----------------------------------------------
|
||||
|
||||
export interface ISmsGetLineResponse extends ISmsResponse {
|
||||
data: string[];
|
||||
}
|
||||
|
||||
export interface ISmsVerifyResponse extends ISmsResponse {
|
||||
data: { MessageId: number; Cost: number };
|
||||
}
|
||||
|
||||
//----------------------------------------------
|
||||
export interface ISmsVerifyBody {
|
||||
Parameters: IParameterArray[];
|
||||
Mobile: string;
|
||||
TemplateId: string;
|
||||
}
|
||||
|
||||
export type TemplateParams =
|
||||
| "VERIFICATIONCODE"
|
||||
| "code"
|
||||
| "invoiceId"
|
||||
| "price"
|
||||
| "items"
|
||||
| "loginDate"
|
||||
| "invoiceDate"
|
||||
| "title"
|
||||
| "description"
|
||||
| "ticketId"
|
||||
| "serviceName"
|
||||
| "date"
|
||||
| "amount"
|
||||
| "newBalance"
|
||||
| "reason"
|
||||
| "dueDate"
|
||||
| "lateFee"
|
||||
| "paidDate"
|
||||
| "user"
|
||||
| "subject"
|
||||
| "planName"
|
||||
| "message"
|
||||
| "blogTitle"
|
||||
| "fullName"
|
||||
| "mobile";
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
import { CACHE_MANAGER, Cache } from "@nestjs/cache-manager";
|
||||
import { Inject, Injectable } from "@nestjs/common";
|
||||
|
||||
@Injectable()
|
||||
export class CacheService {
|
||||
constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}
|
||||
|
||||
async get<T>(key: string) {
|
||||
return await this.cacheManager.get<T>(key);
|
||||
}
|
||||
|
||||
async set(key: string, value: string, ttl: number = 120 * 1000) {
|
||||
await this.cacheManager.set(key, value, ttl);
|
||||
}
|
||||
|
||||
async del(key: string) {
|
||||
await this.cacheManager.del(key);
|
||||
}
|
||||
|
||||
async getTtl(key: string) {
|
||||
return await this.cacheManager.ttl(key);
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
export function numberFormat(number: number, locale: string = "fa-IR") {
|
||||
return Intl.NumberFormat(locale).format(number);
|
||||
}
|
||||
|
||||
export function dateFormat(date: Date | string | number, locale: string = "fa-IR") {
|
||||
try {
|
||||
// Convert to Date object if it's a string or number
|
||||
const dateObj = date instanceof Date ? date : new Date(date);
|
||||
|
||||
// Check if the date is valid
|
||||
if (isNaN(dateObj.getTime())) {
|
||||
console.warn("Invalid date provided to dateFormat:", date);
|
||||
return "Invalid Date";
|
||||
}
|
||||
|
||||
return new Intl.DateTimeFormat(locale).format(dateObj);
|
||||
} catch (error) {
|
||||
console.error("Error formatting date:", error);
|
||||
return "Invalid Date";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Message utility for handling dynamic string replacement in Farsi messages
|
||||
*/
|
||||
|
||||
/**
|
||||
* Replace placeholders in a message string with actual values
|
||||
* @param message The message template with placeholders like [name], [value], etc.
|
||||
* @param replacements Object containing key-value pairs for replacement
|
||||
* @returns The message with placeholders replaced by actual values
|
||||
*
|
||||
* @example
|
||||
* replaceMessagePlaceholders("دامنه [name] قبلا ثبت شده است", { name: "example.com" })
|
||||
* // Returns: "دامنه example.com قبلا ثبت شده است"
|
||||
*
|
||||
* @example
|
||||
* replaceMessagePlaceholders("یک رکورد MX با نام [name] که به [value] با اولویت [priority] اشاره کند اضافه کنید", {
|
||||
* name: "@",
|
||||
* value: "mail.example.com",
|
||||
* priority: "10"
|
||||
* })
|
||||
* // Returns: "یک رکورد MX با نام @ که به mail.example.com با اولویت 10 اشاره کند اضافه کنید"
|
||||
*/
|
||||
export function replaceMessagePlaceholders(message: string, replacements: Record<string, string | number>): string {
|
||||
let result = message;
|
||||
|
||||
// Replace each placeholder with its corresponding value
|
||||
Object.entries(replacements).forEach(([key, value]) => {
|
||||
const placeholder = `[${key}]`;
|
||||
result = result.replace(placeholder, String(value));
|
||||
});
|
||||
console.log("result", result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Common replacement values for domain-related messages
|
||||
*/
|
||||
export interface DomainMessageReplacements {
|
||||
name?: string;
|
||||
value?: string;
|
||||
priority?: string | number;
|
||||
type?: string;
|
||||
count?: string | number;
|
||||
token?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function specifically for domain messages
|
||||
* @param message The domain message template
|
||||
* @param replacements Domain-specific replacement values
|
||||
* @returns The message with placeholders replaced
|
||||
*/
|
||||
export function formatDomainMessage(message: string, replacements: DomainMessageReplacements): string {
|
||||
// Filter out undefined values before passing to replaceMessagePlaceholders
|
||||
const filteredReplacements: Record<string, string | number> = {};
|
||||
Object.entries(replacements).forEach(([key, value]) => {
|
||||
if (value !== undefined) {
|
||||
filteredReplacements[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
return replaceMessagePlaceholders(message, filteredReplacements);
|
||||
}
|
||||
Executable
+44
@@ -0,0 +1,44 @@
|
||||
import { randomInt } from "node:crypto";
|
||||
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
import { CacheService } from "./cache.service";
|
||||
import { OtpCacheKeyType } from "../interfaces/IOtpKey";
|
||||
|
||||
@Injectable()
|
||||
export class OTPService {
|
||||
constructor(private cacheService: CacheService) {}
|
||||
//
|
||||
private generateOTP(): string {
|
||||
return randomInt(10000, 99999).toString();
|
||||
}
|
||||
//
|
||||
async generateAndSetInCache(identifier: string, cacheKey: OtpCacheKeyType) {
|
||||
const otp = this.generateOTP();
|
||||
const key = `${identifier}:${cacheKey}:OTP`;
|
||||
await this.cacheService.set(key, otp, 180 * 1000);
|
||||
return otp;
|
||||
}
|
||||
//
|
||||
async verifyOtp(identifier: string, otpCode: string, cacheKey: OtpCacheKeyType) {
|
||||
const key = `${identifier}:${cacheKey}:OTP`;
|
||||
const codeInCache = await this.cacheService.get<string | null>(key);
|
||||
return codeInCache && otpCode === codeInCache;
|
||||
}
|
||||
//
|
||||
async delOtpFormCache(identifier: string, cacheKey: OtpCacheKeyType) {
|
||||
const key = `${identifier}:${cacheKey}:OTP`;
|
||||
await this.cacheService.del(key);
|
||||
}
|
||||
|
||||
async checkExistOtp(identifier: string, cacheKey: OtpCacheKeyType) {
|
||||
const key = `${identifier}:${cacheKey}:OTP`;
|
||||
const codeInCache = await this.cacheService.get<string | null>(key);
|
||||
|
||||
if (!codeInCache) return null;
|
||||
|
||||
const ttlInMsSeconds = await this.cacheService.getTtl(key);
|
||||
|
||||
return Math.floor((ttlInMsSeconds! - Date.now()) / 1000);
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import { PaginationDto } from "../../../common/DTO/pagination.dto";
|
||||
|
||||
export function PaginationUtils(paginationData: PaginationDto) {
|
||||
const { limit = 10, page = 1 } = paginationData;
|
||||
|
||||
// const pageN = Number.parseInt(page) || 1;
|
||||
// const limitN = Number.parseInt(limit) || 10;
|
||||
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
return {
|
||||
// page: page,
|
||||
// limit: limit > 50 ? 50 : limit,
|
||||
limit: limit,
|
||||
skip: skip,
|
||||
};
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import * as bcrypt from "bcrypt";
|
||||
|
||||
@Injectable()
|
||||
export class PasswordService {
|
||||
private readonly saltRounds = 12;
|
||||
|
||||
async hashPassword(password: string): Promise<string> {
|
||||
return bcrypt.hash(password, this.saltRounds);
|
||||
}
|
||||
|
||||
async comparePasswords(plainPassword: string, hashedPassword: string): Promise<boolean> {
|
||||
return bcrypt.compare(plainPassword, hashedPassword);
|
||||
}
|
||||
}
|
||||
Executable
+542
@@ -0,0 +1,542 @@
|
||||
import { HttpService } from "@nestjs/axios";
|
||||
import { Inject, Injectable, InternalServerErrorException, Logger } from "@nestjs/common";
|
||||
import { AxiosError } from "axios";
|
||||
import { catchError, firstValueFrom } from "rxjs";
|
||||
|
||||
import { SmsMessage } from "../../../common/enums/message.enum";
|
||||
import { ISmsConfigs } from "../../../configs/sms.config";
|
||||
import { SMS_CONFIG } from "../constants";
|
||||
import { ISmsGetLineResponse, ISmsVerifyBody, ISmsVerifyResponse } from "../interfaces/ISms";
|
||||
|
||||
@Injectable()
|
||||
export class SmsService {
|
||||
private readonly logger = new Logger(SmsService.name);
|
||||
|
||||
constructor(
|
||||
@Inject(SMS_CONFIG) private smsConfigs: ISmsConfigs,
|
||||
private readonly httpService: HttpService,
|
||||
) {}
|
||||
//************************************************* */
|
||||
|
||||
async sendSmsVerifyCode(mobile: string, otpCode: string) {
|
||||
//
|
||||
const smsData: ISmsVerifyBody = {
|
||||
Parameters: [{ name: "code", value: otpCode }],
|
||||
Mobile: mobile,
|
||||
TemplateId: this.smsConfigs.SMS_PATTERN_OTP,
|
||||
};
|
||||
//
|
||||
try {
|
||||
const { data } = await firstValueFrom(
|
||||
this.httpService
|
||||
.post<ISmsVerifyResponse>(
|
||||
`${this.smsConfigs.API_URL}/send/verify`,
|
||||
{ ...smsData },
|
||||
{
|
||||
headers: { "X-API-KEY": this.smsConfigs.API_KEY },
|
||||
},
|
||||
)
|
||||
.pipe(
|
||||
catchError((err: AxiosError) => {
|
||||
this.logger.error("error in sending verify sms", err);
|
||||
throw new InternalServerErrorException("error in sending verify sms");
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
return data;
|
||||
} catch (error) {
|
||||
this.logger.error("error in sending sms", error);
|
||||
throw new InternalServerErrorException(SmsMessage.SEND_SMS_ERROR);
|
||||
}
|
||||
}
|
||||
//************************************************* */
|
||||
|
||||
async sendInvoiceVerifyCode(mobile: string, otpCode: string, invoiceId: number, price: number, items: string) {
|
||||
const smsData: ISmsVerifyBody = {
|
||||
Parameters: [
|
||||
{ name: "code", value: otpCode },
|
||||
{ name: "invoiceId", value: invoiceId.toString() },
|
||||
{ name: "price", value: Intl.NumberFormat("fa-IR").format(price) },
|
||||
{ name: "items", value: items },
|
||||
],
|
||||
Mobile: mobile,
|
||||
TemplateId: this.smsConfigs.SMS_PATTERN_INVOICE,
|
||||
};
|
||||
try {
|
||||
const { data } = await firstValueFrom(
|
||||
this.httpService
|
||||
.post<ISmsVerifyResponse>(
|
||||
`${this.smsConfigs.API_URL}/send/verify`,
|
||||
{ ...smsData },
|
||||
{
|
||||
headers: { "X-API-KEY": this.smsConfigs.API_KEY },
|
||||
},
|
||||
)
|
||||
.pipe(
|
||||
catchError((err: AxiosError) => {
|
||||
this.logger.error("error in sending verify sms", err);
|
||||
throw new InternalServerErrorException("error in sending verify sms");
|
||||
}),
|
||||
),
|
||||
);
|
||||
return data;
|
||||
} catch (error) {
|
||||
this.logger.error("error in sending sms", error);
|
||||
throw new InternalServerErrorException(SmsMessage.SEND_SMS_ERROR);
|
||||
}
|
||||
}
|
||||
//************************************************* */
|
||||
|
||||
async sendLoginSms(mobile: string, loginDate: string) {
|
||||
const smsData: ISmsVerifyBody = {
|
||||
Parameters: [{ name: "loginDate", value: loginDate }],
|
||||
Mobile: mobile,
|
||||
TemplateId: this.smsConfigs.SMS_PATTERN_LOGIN,
|
||||
};
|
||||
|
||||
try {
|
||||
const { data } = await firstValueFrom(
|
||||
this.httpService
|
||||
.post<ISmsVerifyResponse>(`${this.smsConfigs.API_URL}/send/verify`, smsData, {
|
||||
headers: { "X-API-KEY": this.smsConfigs.API_KEY },
|
||||
})
|
||||
.pipe(
|
||||
catchError((err: AxiosError) => {
|
||||
this.logger.error("error in sending verify sms", err);
|
||||
throw new InternalServerErrorException("error in sending verify sms");
|
||||
}),
|
||||
),
|
||||
);
|
||||
return data;
|
||||
} catch (error) {
|
||||
this.logger.error("error in sending sms", error);
|
||||
}
|
||||
}
|
||||
//************************************************* */
|
||||
|
||||
async sendInvoiceCreationSms(mobile: string, invoiceId: string, price: number, items: string, invoiceDate: string, dueDate: string) {
|
||||
const smsData: ISmsVerifyBody = {
|
||||
Parameters: [
|
||||
{ name: "invoiceId", value: invoiceId },
|
||||
{ name: "price", value: Intl.NumberFormat("fa-IR").format(price) },
|
||||
{ name: "items", value: items },
|
||||
{ name: "invoiceDate", value: invoiceDate },
|
||||
{ name: "dueDate", value: dueDate },
|
||||
],
|
||||
Mobile: mobile,
|
||||
TemplateId: this.smsConfigs.SMS_PATTERN_INVOICE_CREATED,
|
||||
};
|
||||
|
||||
try {
|
||||
const { data } = await firstValueFrom(
|
||||
this.httpService
|
||||
.post<ISmsVerifyResponse>(`${this.smsConfigs.API_URL}/send/verify`, smsData, {
|
||||
headers: { "X-API-KEY": this.smsConfigs.API_KEY },
|
||||
})
|
||||
.pipe(
|
||||
catchError((err: AxiosError) => {
|
||||
console.error(err);
|
||||
|
||||
this.logger.error("error in sending invoice created sms", err);
|
||||
throw new InternalServerErrorException("error in sending invoice created sms");
|
||||
}),
|
||||
),
|
||||
);
|
||||
return data;
|
||||
} catch (error) {
|
||||
this.logger.error("error in sending sms", error);
|
||||
}
|
||||
}
|
||||
//************************************************* */
|
||||
async sendAnnouncementSms(mobile: string, title: string, description: string, date: string) {
|
||||
const smsData: ISmsVerifyBody = {
|
||||
Parameters: [
|
||||
{ name: "title", value: title },
|
||||
{ name: "description", value: description },
|
||||
{ name: "date", value: date },
|
||||
],
|
||||
Mobile: mobile,
|
||||
TemplateId: this.smsConfigs.SMS_PATTERN_ANNOUNCEMENT,
|
||||
};
|
||||
|
||||
try {
|
||||
const { data } = await firstValueFrom(
|
||||
this.httpService
|
||||
.post<ISmsVerifyResponse>(`${this.smsConfigs.API_URL}/send/verify`, smsData, {
|
||||
headers: { "X-API-KEY": this.smsConfigs.API_KEY },
|
||||
})
|
||||
.pipe(
|
||||
catchError((err: AxiosError) => {
|
||||
this.logger.error("error in sending announcement sms", err);
|
||||
throw new InternalServerErrorException("error in sending announcement sms");
|
||||
}),
|
||||
),
|
||||
);
|
||||
return data;
|
||||
} catch (error) {
|
||||
this.logger.error("error in sending sms", error);
|
||||
}
|
||||
}
|
||||
|
||||
//************************************************* */
|
||||
|
||||
async sendCreateTicketSms(mobile: string, ticketId: string, subject: string, date: string) {
|
||||
const smsData: ISmsVerifyBody = {
|
||||
Parameters: [
|
||||
{ name: "ticketId", value: ticketId },
|
||||
{ name: "subject", value: subject },
|
||||
{ name: "date", value: date },
|
||||
],
|
||||
Mobile: mobile,
|
||||
TemplateId: this.smsConfigs.SMS_PATTERN_TICKET_CREATED,
|
||||
};
|
||||
|
||||
try {
|
||||
const { data } = await firstValueFrom(
|
||||
this.httpService
|
||||
.post<ISmsVerifyResponse>(`${this.smsConfigs.API_URL}/send/verify`, smsData, {
|
||||
headers: { "X-API-KEY": this.smsConfigs.API_KEY },
|
||||
})
|
||||
.pipe(
|
||||
catchError((err: AxiosError) => {
|
||||
this.logger.error("error in sending ticket created sms", err);
|
||||
throw new InternalServerErrorException("error in sending ticket created sms");
|
||||
}),
|
||||
),
|
||||
);
|
||||
return data;
|
||||
} catch (error) {
|
||||
this.logger.error("error in sending sms", error);
|
||||
}
|
||||
}
|
||||
//************************************************* */
|
||||
|
||||
async sendAnswerTicketSms(mobile: string, ticketId: string, subject: string) {
|
||||
const smsData: ISmsVerifyBody = {
|
||||
Parameters: [
|
||||
{ name: "ticketId", value: ticketId },
|
||||
{ name: "subject", value: subject },
|
||||
],
|
||||
Mobile: mobile,
|
||||
TemplateId: this.smsConfigs.SMS_PATTERN_TICKET_ANSWERED,
|
||||
};
|
||||
|
||||
try {
|
||||
const { data } = await firstValueFrom(
|
||||
this.httpService
|
||||
.post<ISmsVerifyResponse>(`${this.smsConfigs.API_URL}/send/verify`, smsData, {
|
||||
headers: { "X-API-KEY": this.smsConfigs.API_KEY },
|
||||
})
|
||||
.pipe(
|
||||
catchError((err: AxiosError) => {
|
||||
this.logger.error("error in sending ticket answered sms", err);
|
||||
throw new InternalServerErrorException("error in sending ticket answered sms");
|
||||
}),
|
||||
),
|
||||
);
|
||||
return data;
|
||||
} catch (error) {
|
||||
this.logger.error("error in sending sms", error);
|
||||
}
|
||||
}
|
||||
//************************************************* */
|
||||
|
||||
async sendTicketAssignedToAdminSms(mobile: string, ticketId: string, subject: string, user: string) {
|
||||
const smsData: ISmsVerifyBody = {
|
||||
Parameters: [
|
||||
{ name: "ticketId", value: ticketId },
|
||||
{ name: "subject", value: subject },
|
||||
{ name: "user", value: user },
|
||||
],
|
||||
Mobile: mobile,
|
||||
TemplateId: this.smsConfigs.SMS_PATTERN_TICKET_ASSIGNED_ADMIN,
|
||||
};
|
||||
|
||||
try {
|
||||
const { data } = await firstValueFrom(
|
||||
this.httpService
|
||||
.post<ISmsVerifyResponse>(`${this.smsConfigs.API_URL}/send/verify`, smsData, {
|
||||
headers: { "X-API-KEY": this.smsConfigs.API_KEY },
|
||||
})
|
||||
.pipe(
|
||||
catchError((err: AxiosError) => {
|
||||
this.logger.error("error in sending ticket assigned sms", err);
|
||||
throw new InternalServerErrorException("error in sending ticket assigned sms");
|
||||
}),
|
||||
),
|
||||
);
|
||||
return data;
|
||||
} catch (error) {
|
||||
this.logger.error("error in sending sms", error);
|
||||
}
|
||||
}
|
||||
//************************************************* */
|
||||
async sendInvoiceApprovedSms(mobile: string, invoiceId: string, price: number, dueDate: string) {
|
||||
const smsData: ISmsVerifyBody = {
|
||||
Parameters: [
|
||||
{ name: "invoiceId", value: invoiceId },
|
||||
{ name: "price", value: Intl.NumberFormat("fa-IR").format(price) },
|
||||
{ name: "dueDate", value: dueDate },
|
||||
],
|
||||
Mobile: mobile,
|
||||
TemplateId: this.smsConfigs.SMS_PATTERN_INVOICE_APPROVED,
|
||||
};
|
||||
|
||||
try {
|
||||
const { data } = await firstValueFrom(
|
||||
this.httpService
|
||||
.post<ISmsVerifyResponse>(`${this.smsConfigs.API_URL}/send/verify`, smsData, {
|
||||
headers: { "X-API-KEY": this.smsConfigs.API_KEY },
|
||||
})
|
||||
.pipe(
|
||||
catchError((err: AxiosError) => {
|
||||
this.logger.error("error in sending invoice approved sms", err);
|
||||
throw new InternalServerErrorException("error in sending invoice approved sms");
|
||||
}),
|
||||
),
|
||||
);
|
||||
return data;
|
||||
} catch (error) {
|
||||
this.logger.error("error in sending sms", error);
|
||||
// throw new InternalServerErrorException("error in sending sms");
|
||||
}
|
||||
}
|
||||
//************************************************* */
|
||||
async sendInvoicePaidSms(mobile: string, invoiceId: string, amount: number, paidDate: string) {
|
||||
const smsData: ISmsVerifyBody = {
|
||||
Parameters: [
|
||||
{ name: "invoiceId", value: invoiceId },
|
||||
{ name: "amount", value: amount.toString() },
|
||||
{ name: "paidDate", value: paidDate },
|
||||
],
|
||||
Mobile: mobile,
|
||||
TemplateId: this.smsConfigs.SMS_PATTERN_INVOICE_PAID,
|
||||
};
|
||||
|
||||
try {
|
||||
const { data } = await firstValueFrom(
|
||||
this.httpService
|
||||
.post<ISmsVerifyResponse>(`${this.smsConfigs.API_URL}/send/verify`, smsData, {
|
||||
headers: { "X-API-KEY": this.smsConfigs.API_KEY },
|
||||
})
|
||||
.pipe(
|
||||
catchError((err: AxiosError) => {
|
||||
this.logger.error("error in sending invoice paid sms", err);
|
||||
throw new InternalServerErrorException("error in sending invoice paid sms");
|
||||
}),
|
||||
),
|
||||
);
|
||||
return data;
|
||||
} catch (error) {
|
||||
this.logger.error("error in sending sms", error);
|
||||
// throw new InternalServerErrorException("error in sending sms");
|
||||
}
|
||||
}
|
||||
|
||||
//************************************************* */
|
||||
|
||||
async sendInvoicePaymentReminderSms(mobile: string, invoiceId: string, amount: number, dueDate: string) {
|
||||
const smsData: ISmsVerifyBody = {
|
||||
Parameters: [
|
||||
{ name: "invoiceId", value: invoiceId },
|
||||
{ name: "amount", value: amount.toString() },
|
||||
{ name: "dueDate", value: dueDate },
|
||||
],
|
||||
Mobile: mobile,
|
||||
TemplateId: this.smsConfigs.SMS_PATTERN_INVOICE_REMINDER,
|
||||
};
|
||||
|
||||
try {
|
||||
const { data } = await firstValueFrom(
|
||||
this.httpService
|
||||
.post<ISmsVerifyResponse>(`${this.smsConfigs.API_URL}/send/verify`, smsData, {
|
||||
headers: { "X-API-KEY": this.smsConfigs.API_KEY },
|
||||
})
|
||||
.pipe(
|
||||
catchError((err: AxiosError) => {
|
||||
this.logger.error("error in sending invoice reminder sms", err);
|
||||
throw new InternalServerErrorException("error in sending invoice reminder sms");
|
||||
}),
|
||||
),
|
||||
);
|
||||
return data;
|
||||
} catch (error) {
|
||||
this.logger.error("error in sending sms", error);
|
||||
}
|
||||
}
|
||||
|
||||
//************************************************* */
|
||||
|
||||
async sendInvoiceOverdueSms(mobile: string, invoiceId: string, amount: number, lateFee: number, dueDate: string) {
|
||||
const smsData: ISmsVerifyBody = {
|
||||
Parameters: [
|
||||
{ name: "invoiceId", value: invoiceId },
|
||||
{ name: "amount", value: amount.toString() },
|
||||
{ name: "lateFee", value: lateFee.toString() },
|
||||
{ name: "dueDate", value: dueDate },
|
||||
],
|
||||
Mobile: mobile,
|
||||
TemplateId: this.smsConfigs.SMS_PATTERN_INVOICE_OVERDUE,
|
||||
};
|
||||
|
||||
try {
|
||||
const { data } = await firstValueFrom(
|
||||
this.httpService
|
||||
.post<ISmsVerifyResponse>(`${this.smsConfigs.API_URL}/send/verify`, smsData, {
|
||||
headers: { "X-API-KEY": this.smsConfigs.API_KEY },
|
||||
})
|
||||
.pipe(
|
||||
catchError((err: AxiosError) => {
|
||||
this.logger.error("error in sending invoice overdue sms", err);
|
||||
throw new InternalServerErrorException("error in sending invoice overdue sms");
|
||||
}),
|
||||
),
|
||||
);
|
||||
return data;
|
||||
} catch (error) {
|
||||
this.logger.error("error in sending sms", error);
|
||||
}
|
||||
}
|
||||
|
||||
//************************************************* */
|
||||
|
||||
async sendRecurringInvoiceDraftSms(adminMobile: string, invoiceId: string, price: number) {
|
||||
const smsData: ISmsVerifyBody = {
|
||||
Parameters: [
|
||||
{ name: "invoiceId", value: invoiceId },
|
||||
{ name: "price", value: Intl.NumberFormat("fa-IR").format(price) },
|
||||
],
|
||||
Mobile: adminMobile,
|
||||
TemplateId: this.smsConfigs.SMS_PATTERN_RECURRING_INVOICE_DRAFT,
|
||||
};
|
||||
|
||||
try {
|
||||
const { data } = await firstValueFrom(
|
||||
this.httpService
|
||||
.post<ISmsVerifyResponse>(`${this.smsConfigs.API_URL}/send/verify`, smsData, {
|
||||
headers: { "X-API-KEY": this.smsConfigs.API_KEY },
|
||||
})
|
||||
.pipe(
|
||||
catchError((err: AxiosError) => {
|
||||
this.logger.error("error in sending recurring invoice draft sms", err);
|
||||
throw new InternalServerErrorException("error in sending recurring invoice draft sms");
|
||||
}),
|
||||
),
|
||||
);
|
||||
return data;
|
||||
} catch (error) {
|
||||
this.logger.error("error in sending sms", error);
|
||||
// throw new InternalServerErrorException("error in sending sms");
|
||||
}
|
||||
}
|
||||
|
||||
//************************************************* */
|
||||
|
||||
async sendBlockServiceSms(mobile: string, invoiceId: string, planName: string) {
|
||||
const smsData: ISmsVerifyBody = {
|
||||
Parameters: [
|
||||
{ name: "invoiceId", value: invoiceId },
|
||||
{ name: "planName", value: planName },
|
||||
],
|
||||
Mobile: mobile,
|
||||
TemplateId: this.smsConfigs.SMS_PATTERN_SUBSCRIPTION_CANCELLED,
|
||||
};
|
||||
|
||||
try {
|
||||
const { data } = await firstValueFrom(
|
||||
this.httpService
|
||||
.post<ISmsVerifyResponse>(`${this.smsConfigs.API_URL}/send/verify`, smsData, {
|
||||
headers: { "X-API-KEY": this.smsConfigs.API_KEY },
|
||||
})
|
||||
.pipe(
|
||||
catchError((err: AxiosError) => {
|
||||
this.logger.error("error in sending subscription cancelled sms", err);
|
||||
throw new InternalServerErrorException("error in sending subscription cancelled sms");
|
||||
}),
|
||||
),
|
||||
);
|
||||
return data;
|
||||
} catch (error) {
|
||||
this.logger.error("error in sending sms", error);
|
||||
// throw new InternalServerErrorException("error in sending sms");
|
||||
}
|
||||
}
|
||||
|
||||
//************************************************* */
|
||||
//************************************************* */
|
||||
|
||||
async sendPaymentReminderSms(mobile: string, amount: string) {
|
||||
const smsData: ISmsVerifyBody = {
|
||||
Parameters: [{ name: "amount", value: amount }],
|
||||
Mobile: mobile,
|
||||
TemplateId: this.smsConfigs.SMS_PATTERN_PAYMENT_REMINDER,
|
||||
};
|
||||
|
||||
try {
|
||||
const { data } = await firstValueFrom(
|
||||
this.httpService
|
||||
.post<ISmsVerifyResponse>(`${this.smsConfigs.API_URL}/send/verify`, smsData, {
|
||||
headers: { "X-API-KEY": this.smsConfigs.API_KEY },
|
||||
})
|
||||
.pipe(
|
||||
catchError((err: AxiosError) => {
|
||||
this.logger.error("error in sending payment reminder sms", err);
|
||||
throw new InternalServerErrorException("error in sending payment reminder sms");
|
||||
}),
|
||||
),
|
||||
);
|
||||
return data;
|
||||
} catch (error) {
|
||||
this.logger.error("error in sending sms", error);
|
||||
}
|
||||
}
|
||||
//************************************************* */
|
||||
|
||||
async sendPaymentCancellationSms(mobile: string, amount: string) {
|
||||
const smsData: ISmsVerifyBody = {
|
||||
Parameters: [{ name: "amount", value: amount }],
|
||||
Mobile: mobile,
|
||||
TemplateId: this.smsConfigs.SMS_PATTERN_PAYMENT_CANCELLATION,
|
||||
};
|
||||
|
||||
try {
|
||||
const { data } = await firstValueFrom(
|
||||
this.httpService
|
||||
.post<ISmsVerifyResponse>(`${this.smsConfigs.API_URL}/send/verify`, smsData, {
|
||||
headers: { "X-API-KEY": this.smsConfigs.API_KEY },
|
||||
})
|
||||
.pipe(
|
||||
catchError((err: AxiosError) => {
|
||||
this.logger.error("error in sending payment cancellation sms", err);
|
||||
throw new InternalServerErrorException("error in sending payment cancellation sms");
|
||||
}),
|
||||
),
|
||||
);
|
||||
return data;
|
||||
} catch (error) {
|
||||
this.logger.error("error in sending sms", error);
|
||||
}
|
||||
}
|
||||
|
||||
async getSmsLines() {
|
||||
try {
|
||||
const { data } = await firstValueFrom(
|
||||
this.httpService
|
||||
.get<ISmsGetLineResponse>(`${this.smsConfigs.API_URL}/lines`, {
|
||||
headers: { "X-API-KEY": this.smsConfigs.API_KEY },
|
||||
})
|
||||
.pipe(
|
||||
catchError((error: AxiosError) => {
|
||||
this.logger.error("error in getting sms lines", error);
|
||||
throw new InternalServerErrorException("error in getting sms lines");
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
return data;
|
||||
} catch (error) {
|
||||
this.logger.error("error in getting sms lines", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
|
||||
import { S3_CONFIG, SMS_CONFIG } from "./constants";
|
||||
import { CacheService } from "./services/cache.service";
|
||||
import { OTPService } from "./services/otp.service";
|
||||
import { PasswordService } from "./services/password.service";
|
||||
import { SmsService } from "./services/sms.service";
|
||||
import { S3Configs } from "../../configs/s3.config";
|
||||
import { smsConfigs } from "../../configs/sms.config";
|
||||
|
||||
@Module({
|
||||
providers: [
|
||||
OTPService,
|
||||
PasswordService,
|
||||
CacheService,
|
||||
SmsService,
|
||||
{
|
||||
provide: SMS_CONFIG,
|
||||
useFactory: smsConfigs().useFactory,
|
||||
inject: smsConfigs().inject,
|
||||
},
|
||||
{
|
||||
provide: S3_CONFIG,
|
||||
useFactory: S3Configs().useFactory,
|
||||
inject: S3Configs().inject,
|
||||
},
|
||||
],
|
||||
exports: [SMS_CONFIG, S3_CONFIG, OTPService, PasswordService, CacheService, SmsService],
|
||||
})
|
||||
export class UtilsModule {}
|
||||
Reference in New Issue
Block a user