diff --git a/backend/src/admin/admin.service.ts b/backend/src/admin/admin.service.ts
index 6c48a97..aa7737f 100644
--- a/backend/src/admin/admin.service.ts
+++ b/backend/src/admin/admin.service.ts
@@ -984,6 +984,32 @@ export class AdminService {
});
});
+ // Send SMS notification for wallet refund
+ if (this.smsService && order.user?.mobile) {
+ try {
+ const user = await this.prisma.user.findUnique({
+ where: { id: order.userId },
+ });
+ const customerFullName = (
+ order.user.firstName
+ ? `${order.user.firstName} ${order.user.lastName || ''}`
+ : 'کاربر گرامی'
+ ).trim();
+ const refundData = {
+ customerName: customerFullName,
+ customerPhone: order.user.mobile,
+ amount: Number(refundAmount || 0).toLocaleString('fa-IR'),
+ balance: Number(user?.walletBalance || 0).toLocaleString('fa-IR'),
+ reason: reason || `استرداد وجه سفارش #${order.trackingNumber || order.id.slice(0, 8)}`,
+ date: new Date().toLocaleDateString('fa-IR'),
+ };
+
+ this.smsService.triggerEvent('WALLET_CHARGED', refundData).catch(() => {});
+ } catch (err) {
+ // Silently catch SMS errors
+ }
+ }
+
return {
success: true,
message: `مبلغ ${refundAmount.toLocaleString('fa-IR')} تومان با موفقیت به کیف پول کاربر بازگردانده شد.`,
@@ -1243,7 +1269,7 @@ export class AdminService {
});
const isIncrement = type === 'deposit' || type === 'refund';
- await this.prisma.user.update({
+ const updatedUser = await this.prisma.user.update({
where: { id: userId },
data: {
walletBalance: isIncrement
@@ -1252,6 +1278,31 @@ export class AdminService {
},
});
+ // Send SMS notification if wallet is topped up or refunded
+ if (isIncrement && this.smsService && updatedUser.mobile) {
+ try {
+ const customerFullName = (
+ updatedUser.firstName
+ ? `${updatedUser.firstName} ${updatedUser.lastName || ''}`
+ : 'کاربر گرامی'
+ ).trim();
+ const topupData = {
+ customerName: customerFullName,
+ customerPhone: updatedUser.mobile,
+ amount: Number(amount || 0).toLocaleString('fa-IR'),
+ balance: Number(updatedUser.walletBalance || 0).toLocaleString('fa-IR'),
+ reason: description || (type === 'refund' ? 'استرداد وجه به کیف پول' : 'شارژ کیف پول توسط مدیریت'),
+ date: new Date().toLocaleDateString('fa-IR'),
+ };
+
+ this.smsService
+ .triggerEvent('WALLET_CHARGED', topupData)
+ .catch(() => {});
+ } catch (err) {
+ // Silently catch SMS errors
+ }
+ }
+
return transaction;
}
diff --git a/backend/src/common/services/sms-events.constants.ts b/backend/src/common/services/sms-events.constants.ts
index 9e0a473..fde587a 100644
--- a/backend/src/common/services/sms-events.constants.ts
+++ b/backend/src/common/services/sms-events.constants.ts
@@ -104,6 +104,19 @@ export const SMS_EVENT_DEFINITIONS: SmsEventDefinition[] = [
{ key: 'date', label: 'تاریخ ارسال', sample: '۱۴۰۳/۰۶/۱۵' },
],
},
+ {
+ event: 'WALLET_CHARGED',
+ label: 'شارژ و افزایش موجودی کیف پول',
+ description: 'هنگام افزایش موجودی کیف پول کاربر (درگاه آنلاین، پنل مدیریت، کشبک یا استرداد)',
+ variables: [
+ { key: 'customerName', label: 'نام مشتری', sample: 'علی محمدی' },
+ { key: 'amount', label: 'مبلغ شارژ (تومان)', sample: '۵۰,۰۰۰' },
+ { key: 'balance', label: 'موجودی جدید کیف پول (تومان)', sample: '۱۵۰,۰۰۰' },
+ { key: 'reason', label: 'علت / نوع شارژ', sample: 'شارژ آنلاین / پاداش خرید (Cashback)' },
+ { key: 'customerPhone', label: 'شماره همراه مشتری', sample: '09123456789' },
+ { key: 'date', label: 'تاریخ شارژ', sample: '۱۴۰۳/۰۶/۱۵' },
+ ],
+ },
];
export const DEFAULT_SMS_RULES: SmsRule[] = [
@@ -147,4 +160,14 @@ export const DEFAULT_SMS_RULES: SmsRule[] = [
variables: ['applicantName'],
description: 'پیامک ثبت درخواست متقاضیان عمدهفروشی',
},
+ {
+ id: 'default-wallet-charged-customer',
+ title: 'اطلاعرسانی شارژ کیف پول به کاربر',
+ event: 'WALLET_CHARGED',
+ enabled: true,
+ recipientType: 'customer',
+ patternId: 0,
+ variables: ['customerName', 'amount', 'balance'],
+ description: 'ارسال پیامک افزایش موجودی کیف پول (آنلاین، مدیریت یا کشبک)',
+ },
];
diff --git a/backend/src/payment/payment.service.ts b/backend/src/payment/payment.service.ts
index 5c3643d..365d434 100644
--- a/backend/src/payment/payment.service.ts
+++ b/backend/src/payment/payment.service.ts
@@ -608,6 +608,38 @@ export class PaymentService {
});
}
+ // Send SMS notification if wallet top-up
+ if (transaction.type === 'WALLET_TOPUP' && transaction.userId) {
+ try {
+ const user = await this.prisma.user.findUnique({
+ where: { id: transaction.userId },
+ });
+ if (user?.mobile) {
+ const customerFullName = (
+ user.firstName
+ ? `${user.firstName} ${user.lastName || ''}`
+ : 'کاربر گرامی'
+ ).trim();
+ const topupData = {
+ customerName: customerFullName,
+ customerPhone: user.mobile,
+ amount: Number(transaction.amount || 0).toLocaleString('fa-IR'),
+ balance: Number(user.walletBalance || 0).toLocaleString('fa-IR'),
+ reason: 'شارژ آنلاین از طریق درگاه بانکی',
+ date: new Date().toLocaleDateString('fa-IR'),
+ };
+
+ this.smsService
+ .triggerEvent('WALLET_CHARGED', topupData)
+ .catch((err) => {
+ this.logger.warn(`Could not trigger SMS event WALLET_CHARGED: ${err}`);
+ });
+ }
+ } catch (err) {
+ this.logger.warn(`Error dispatching WALLET_CHARGED SMS: ${err}`);
+ }
+ }
+
return {
success: true,
status: 'VERIFIED',
@@ -1075,6 +1107,37 @@ export class PaymentService {
}
});
+ if (transaction.type === 'WALLET_TOPUP' && transaction.userId) {
+ try {
+ const user = await this.prisma.user.findUnique({
+ where: { id: transaction.userId },
+ });
+ if (user?.mobile) {
+ const customerFullName = (
+ user.firstName
+ ? `${user.firstName} ${user.lastName || ''}`
+ : 'کاربر گرامی'
+ ).trim();
+ const topupData = {
+ customerName: customerFullName,
+ customerPhone: user.mobile,
+ amount: Number(transaction.amount || 0).toLocaleString('fa-IR'),
+ balance: Number(user.walletBalance || 0).toLocaleString('fa-IR'),
+ reason: adminNote || 'افزایش موجودی (کارت به کارت / فیش بانکی)',
+ date: new Date().toLocaleDateString('fa-IR'),
+ };
+
+ this.smsService
+ .triggerEvent('WALLET_CHARGED', topupData)
+ .catch((err) => {
+ this.logger.warn(`Could not trigger SMS event WALLET_CHARGED: ${err}`);
+ });
+ }
+ } catch (err) {
+ this.logger.warn(`Error dispatching WALLET_CHARGED SMS: ${err}`);
+ }
+ }
+
return {
success: true,
message: 'تراکنش با موفقیت به صورت دستی تایید و اعمال شد',
diff --git a/backend/src/users/users.service.ts b/backend/src/users/users.service.ts
index be77356..1e2d06d 100644
--- a/backend/src/users/users.service.ts
+++ b/backend/src/users/users.service.ts
@@ -2,9 +2,11 @@ import {
Injectable,
BadRequestException,
NotFoundException,
+ Optional,
} from '@nestjs/common';
import { Prisma } from '@prisma/client';
import { PrismaService } from '../prisma/prisma.service';
+import { SmsService } from '../common/services/sms.service';
import * as bcrypt from 'bcryptjs';
import { normalizeMobile } from '../common/utils/phone.utils';
import { UpdateProfileDto } from './dto/update-profile.dto';
@@ -22,7 +24,10 @@ export interface UserAddressInput {
@Injectable()
export class UsersService {
- constructor(private prisma: PrismaService) {}
+ constructor(
+ private prisma: PrismaService,
+ @Optional() private smsService?: SmsService,
+ ) {}
async findById(id: string) {
if (id === '12345678-1234-1234-1234-123456789012') {
@@ -277,7 +282,7 @@ export class UsersService {
throw new Error('مبلغ شارژ باید بزرگتر از صفر باشد');
}
- const [transaction] = await this.prisma.$transaction([
+ const [transaction, updatedUser] = await this.prisma.$transaction([
this.prisma.walletTransaction.create({
data: {
userId,
@@ -293,6 +298,28 @@ export class UsersService {
}),
]);
+ if (this.smsService && updatedUser.mobile) {
+ try {
+ const customerFullName = (
+ updatedUser.firstName
+ ? `${updatedUser.firstName} ${updatedUser.lastName || ''}`
+ : 'کاربر گرامی'
+ ).trim();
+ const topupData = {
+ customerName: customerFullName,
+ customerPhone: updatedUser.mobile,
+ amount: Number(amount || 0).toLocaleString('fa-IR'),
+ balance: Number(updatedUser.walletBalance || 0).toLocaleString('fa-IR'),
+ reason: 'افزایش موجودی کیف پول',
+ date: new Date().toLocaleDateString('fa-IR'),
+ };
+
+ this.smsService.triggerEvent('WALLET_CHARGED', topupData).catch(() => {});
+ } catch (err) {
+ // Silently catch SMS error
+ }
+ }
+
return transaction;
}
diff --git a/frontend/admin-panel/src/pages/SmsSettingsPage.tsx b/frontend/admin-panel/src/pages/SmsSettingsPage.tsx
index f6a7ee4..be30a1b 100644
--- a/frontend/admin-panel/src/pages/SmsSettingsPage.tsx
+++ b/frontend/admin-panel/src/pages/SmsSettingsPage.tsx
@@ -2153,6 +2153,7 @@ export default function SmsSettingsPage() {
+
>