All files / src/modules/quick-rent/workers payment-window-expired.processor.ts

86.2% Statements 25/29
66.66% Branches 14/21
100% Functions 3/3
88% Lines 22/25

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 7012x   12x 12x 12x 12x           12x 1x   1x 1x 1x 1x     1x     1x 1x   1x               1x         1x         1x 1x   1x 1x       1x                                  
import { Processor, WorkerHost } from '@nestjs/bullmq';
import { Job } from 'bullmq';
import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '@app/modules/prisma/prisma.service';
import { InjectQueue } from '@nestjs/bullmq';
import { Queue } from 'bullmq';
 
interface ExpiredPayload { requestId: number; bidId: number; rank: number }
 
@Processor('quick-rent:payment-window-expired')
@Injectable()
export class QuickRentPaymentWindowExpiredProcessor extends WorkerHost {
  private readonly logger = new Logger(QuickRentPaymentWindowExpiredProcessor.name);
  constructor(
    private readonly prisma: PrismaService, 
    @InjectQueue('quick-rent:payment-window-expired') private readonly selfQueue: Queue, 
    @InjectQueue('notifications') private readonly notificationsQueue: Queue
  ) { super(); }
 
  async process(job: Job<ExpiredPayload>): Promise<void> {
    const { requestId, bidId, rank } = job.data;
    
    // Get the bid to find bidder and agency info
    const bid = await this.prisma.client.quickRentBid.findUnique({ where: { id: bidId } });
    Iif (!bid) return;
    
    const access = await this.prisma.client.quickRentLeadAccess.findFirst({ 
      where: { 
        requestId, 
        bidderId: bid.bidderId ?? undefined, 
        agencyId: bid.agencyId ?? undefined 
      } 
    });
    
    Iif (access && access.paidAt) {
      return;
    }
    
    // Find next highest bidder
    const bids = await this.prisma.client.quickRentBid.findMany({ 
      where: { requestId }, 
      orderBy: [{ amountCents: 'desc' }, { createdAt: 'asc' }] 
    });
    
    const currentIndex = bids.findIndex((b: { id: number }) => b.id === bidId);
    const next = bids[currentIndex + 1];
    
    if (!next) {
      await this.prisma.client.quickRentRequest.update({ 
        where: { id: requestId }, 
        data: { status: 'EXPIRED' } 
      });
      return;
    }
    
    // Notify next bidder with second-chance offer
    await this.notificationsQueue.add('send', { 
      type: 'QUICK_RENT_SECOND_CHANCE', 
      payload: { requestId, bidId: next.id } 
    });
    
    // Re-enqueue self with next bidder and same 1-hour delay
    await this.selfQueue.add('check', { 
      requestId, 
      bidId: next.id, 
      rank: rank + 1 
    }, { delay: 60 * 60 * 1000 });
  }
}