11import { Processor , Process , OnQueueActive , OnQueueCompleted , OnQueueFailed } from '@nestjs/bull' ;
2-
3- import { Inject , Logger } from '@nestjs/common' ;
2+ import { Inject , Injectable , Logger , Optional } from '@nestjs/common' ;
43import { Job } from 'bull' ;
5- import { Logger } from '@nestjs/common' ;
64import { InjectRepository } from '@nestjs/typeorm' ;
75import { Repository } from 'typeorm' ;
86import { QUEUE_NAMES , JOB_NAMES } from '../../common/constants/queue.constants' ;
97import { SubscriptionsService } from './subscriptions.service' ;
108import { Subscription , SubscriptionStatus } from '../entities/subscription.entity' ;
9+ import { IPaymentProvider } from '../providers/payment-provider.interface' ;
1110
1211export interface ResumeSubscriptionJobData {
1312 subscriptionId : string ;
1413 userId ?: string ;
1514 reason ?: string ;
1615}
17- import { QUEUE_NAMES , JOB_NAMES } from '../../common/constants/queue.constants' ;
18- import { InjectRepository } from '@nestjs/typeorm' ;
19- import { Repository } from 'typeorm' ;
20- import { Subscription , SubscriptionStatus } from '../entities/subscription.entity' ;
21- import { IPaymentProvider } from '../providers/payment-provider.interface' ;
2216
17+ @Injectable ( )
2318@Processor ( QUEUE_NAMES . SUBSCRIPTIONS )
2419export class SubscriptionJobProcessor {
2520 private readonly logger = new Logger ( SubscriptionJobProcessor . name ) ;
@@ -28,21 +23,21 @@ export class SubscriptionJobProcessor {
2823 private readonly subscriptionsService : SubscriptionsService ,
2924 @InjectRepository ( Subscription )
3025 private readonly subscriptionRepository : Repository < Subscription > ,
31- @InjectRepository ( Subscription )
32- private subscriptionRepository : Repository < Subscription > ,
26+ @Optional ( )
3327 @Inject ( 'IPaymentProvider' )
34- private paymentProvider : IPaymentProvider ,
28+ private readonly paymentProvider ? : IPaymentProvider ,
3529 ) { }
3630
3731 @Process ( JOB_NAMES . PROCESS_SUBSCRIPTION )
3832 async handleSubscription ( job : Job < unknown > ) : Promise < unknown > {
39- // Process subscription job
4033 this . logger . log ( 'Processing subscription job:' , job . data ) ;
4134 return { success : true } ;
4235 }
4336
4437 @Process ( JOB_NAMES . RESUME_SUBSCRIPTION )
45- async handleResumeSubscription ( job : Job < ResumeSubscriptionJobData > ) : Promise < unknown > {
38+ async handleResumeSubscription (
39+ job : Job < ResumeSubscriptionJobData > ,
40+ ) : Promise < { success : boolean ; reason ?: string ; message ?: string } > {
4641 const { subscriptionId } = job . data ;
4742 this . logger . log ( `Processing automatic resume for subscription: ${ subscriptionId } ` ) ;
4843
@@ -67,13 +62,25 @@ export class SubscriptionJobProcessor {
6762 }
6863
6964 // Idempotency check: Guard against double-resume or already resumed subscriptions
70- if ( ! subscription . properties ?. isPaused ) {
65+ if ( ! subscription . properties ?. isPaused && subscription . status !== SubscriptionStatus . PAUSED ) {
7166 this . logger . log (
7267 `Subscription ${ subscriptionId } is not paused (already resumed). Skipping auto-resume.` ,
7368 ) ;
7469 return { success : true , reason : 'Subscription not paused' } ;
7570 }
7671
72+ // Resume at provider (Stripe) if provider subscription ID is present
73+ if ( subscription . providerSubscriptionId && this . paymentProvider ?. resumeSubscription ) {
74+ try {
75+ await this . paymentProvider . resumeSubscription ( subscription . providerSubscriptionId ) ;
76+ } catch ( error ) {
77+ this . logger . error (
78+ `Failed to resume subscription ${ subscriptionId } at payment provider: ${ ( error as Error ) . message } ` ,
79+ ) ;
80+ throw error ;
81+ }
82+ }
83+
7784 try {
7885 await this . subscriptionsService . resumeSubscription ( subscriptionId , {
7986 reason : job . data . reason || 'Automatic resume from scheduled pause' ,
@@ -87,63 +94,6 @@ export class SubscriptionJobProcessor {
8794 throw error ;
8895 }
8996 }
90- async handleResumeSubscription (
91- job : Job < { subscriptionId : string } > ,
92- ) : Promise < { success : boolean ; message : string } > {
93- const { subscriptionId } = job . data ;
94-
95- try {
96- this . logger . log ( `Processing resume subscription job for ${ subscriptionId } ` ) ;
97-
98- const subscription = await this . subscriptionRepository . findOne ( {
99- where : { id : subscriptionId } ,
100- } ) ;
101-
102- if ( ! subscription ) {
103- this . logger . error ( `Subscription ${ subscriptionId } not found` ) ;
104- return { success : false , message : 'Subscription not found' } ;
105- }
106-
107- if ( subscription . status !== SubscriptionStatus . PAUSED ) {
108- this . logger . warn (
109- `Subscription ${ subscriptionId } is not paused (status: ${ subscription . status } )` ,
110- ) ;
111- return { success : false , message : 'Subscription is not paused' } ;
112- }
113-
114- if ( ! subscription . providerSubscriptionId ) {
115- this . logger . error ( `Subscription ${ subscriptionId } has no provider subscription ID` ) ;
116- return { success : false , message : 'No provider subscription ID' } ;
117- }
118-
119- // Resume at provider (Stripe) first
120- try {
121- await this . paymentProvider . resumeSubscription ( subscription . providerSubscriptionId ) ;
122- } catch ( error ) {
123- this . logger . error ( `Failed to resume subscription ${ subscriptionId } at provider` , error ) ;
124- return { success : false , message : 'Provider resume failed' } ;
125- }
126-
127- // Resume the subscription locally only after provider succeeds
128- subscription . status = SubscriptionStatus . ACTIVE ;
129- subscription . cancelAtPeriodEnd = false ;
130- subscription . properties = {
131- ...subscription . properties ,
132- isPaused : false ,
133- resumedAt : new Date ( ) ,
134- resumeReason : 'Scheduled automatic resume' ,
135- } ;
136-
137- await this . subscriptionRepository . save ( subscription ) ;
138-
139- this . logger . log ( `Successfully resumed subscription ${ subscriptionId } via scheduled job` ) ;
140-
141- return { success : true , message : 'Subscription resumed successfully' } ;
142- } catch ( error ) {
143- this . logger . error ( `Failed to resume subscription ${ subscriptionId } ` , error ) ;
144- throw error ;
145- }
146- }
14797
14898 @OnQueueActive ( )
14999 onActive ( job : Job ) {
0 commit comments