77 lines
2.7 KiB
TypeScript
77 lines
2.7 KiB
TypeScript
import { Injectable, Logger } from '@nestjs/common';
|
|
import { Cron, CronExpression } from '@nestjs/schedule';
|
|
import { SalonNotificationsService } from '../notifications/salon-notifications.service';
|
|
import { SmsService } from '../sms/sms.service';
|
|
import { SalonSubscriptionsService } from './salon-subscriptions.service';
|
|
|
|
@Injectable()
|
|
export class SubscriptionAutomationService {
|
|
private readonly logger = new Logger(SubscriptionAutomationService.name);
|
|
|
|
constructor(
|
|
private readonly salonSubscriptionsService: SalonSubscriptionsService,
|
|
private readonly salonNotificationsService: SalonNotificationsService,
|
|
private readonly smsService: SmsService,
|
|
) {}
|
|
|
|
/**
|
|
* Detects subscriptions (trial or paid) whose validity period just ended
|
|
* and, once per subscription, notifies the salon owner in-app and by SMS
|
|
* that they need to purchase a plan to keep using the product. Access is
|
|
* already blocked automatically by `ActiveSubscriptionGuard` once the
|
|
* subscription's `endDate` has passed, independent of this job.
|
|
*/
|
|
@Cron(CronExpression.EVERY_DAY_AT_10AM, {
|
|
name: 'subscription-expiry-notifications',
|
|
})
|
|
async notifyExpiredSubscriptions(): Promise<number> {
|
|
const subscriptions =
|
|
await this.salonSubscriptionsService.findSubscriptionsPendingExpiryNotification();
|
|
|
|
let notifiedCount = 0;
|
|
|
|
for (const subscription of subscriptions) {
|
|
try {
|
|
await this.salonSubscriptionsService.markExpiryNotified(
|
|
subscription.id,
|
|
);
|
|
|
|
const planLabel = subscription.plan?.isTrial
|
|
? 'دوره آزمایشی رایگان'
|
|
: `اشتراک ${subscription.plan?.name ?? ''}`.trim();
|
|
|
|
await this.salonNotificationsService.notifySubscriptionExpired({
|
|
salonId: subscription.salonId,
|
|
salonOwnerId: subscription.salon.ownerId,
|
|
salonName: subscription.salon.name,
|
|
planLabel,
|
|
endDate: subscription.endDate,
|
|
});
|
|
|
|
const ownerMobile = subscription.salon.owner?.mobile;
|
|
if (ownerMobile) {
|
|
await this.smsService.sendSms(
|
|
ownerMobile,
|
|
`${planLabel} سالن ${subscription.salon.name} به پایان رسید. برای ادامه استفاده از امکانات و ارسال پیامک، همین حالا اشتراک تهیه کنید.`,
|
|
);
|
|
}
|
|
|
|
notifiedCount += 1;
|
|
} catch (error) {
|
|
this.logger.error(
|
|
`Failed to send expiry notification for subscription ${subscription.id}`,
|
|
error instanceof Error ? error.stack : undefined,
|
|
);
|
|
}
|
|
}
|
|
|
|
if (notifiedCount > 0) {
|
|
this.logger.log(
|
|
`Sent expiry notifications for ${notifiedCount} subscription(s)`,
|
|
);
|
|
}
|
|
|
|
return notifiedCount;
|
|
}
|
|
}
|