All files / src/cronjobs expiry-notification.cronjob.ts

36.17% Statements 17/47
0% Branches 0/24
20% Functions 1/5
34.88% Lines 15/43

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 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 1201x 1x 1x 1x   1x 1x 1x 1x 1x     1x 1x     1x     1x       1x   1x                                                                                                                                                                                            
import { AwsServiceBindings, AwsSesService } from '@logchain/components/aws';
import { Constants } from '@logchain/configs';
import { CompanyRepository } from '@logchain/repositories';
import { NotificationService } from '@logchain/services';
import { AnyObject, RecipientNotification } from '@logchain/types';
import { DateUtils } from '@logchain/utils';
import { inject, service } from '@loopback/core';
import { CronJob, cronJob } from '@loopback/cron';
import { PositionalParameters, repository } from '@loopback/repository';
import moment from 'moment';
 
@cronJob()
export class ExpiryNotificationCronJob extends CronJob {
  private readonly lock_key = '1747629046';
 
  @inject(AwsServiceBindings.SES_SERVICE)
  public ses_service: AwsSesService;
 
  @service()
  public notification_service: NotificationService;
  
  constructor(
    @repository(CompanyRepository)
    public companyRepository: CompanyRepository,
  ) {
    super({
      name: 'Expiry Notification',
      onTick: () => {
        this.performCronJob().catch(err => {
          console.error('Error in ExpiryNotificationCronJob:', err);
        });
      },
      cronTime: '0 15 2 * * *', // Daily at 2:15 AM server time
      // cronTime: '0 */10 * * * *', // Every 10 minutes
      start: true,
    });
  }
 
  async performCronJob() {
    const isUnLocked = await this.companyRepository.execute(`SELECT pg_try_advisory_lock(${this.lock_key});`);
    if (!isUnLocked[0].pg_try_advisory_lock) {
      return;
    }
 
    await this.companyRepository.execute(`SELECT pg_advisory_unlock(${this.lock_key});`);
    const now = moment();
    const startAt = now.toDate();
    console.log(`*** Cronjob: ${this.name} started at ${startAt}`);
    // Your code start here
    const sql = `
    SELECT DISTINCT ON (u.company_id)
      cl.company_id,
      cl.end_date,
      co."name" as company_name,
      u."name" as admin_name,
      u.contact_email,
      u."language",
      u.settings,
      u.sub
    FROM users_view u
    INNER JOIN company_licences cl ON cl.company_id = u.company_id
    INNER JOIN companies co ON co.id = cl.company_id
    WHERE is_admin = TRUE 
    AND u.status = 2
    AND cl.status = 1
    AND cl.end_date <= CURRENT_DATE + INTERVAL '0 days'
    ORDER BY u.company_id, cl.created_date DESC;
    `;
    const params: PositionalParameters = [];
    const records = await this.companyRepository.execute(sql, params) as AnyObject[];
    const recepients = [];
    const identities: RecipientNotification[] = [];
    const company_ids = records.map(record => record.company_id) ?? [];
    const p_tasks = [];
    if (records?.length) {
      for(const record of records) {
        identities.push({
          sub: record.sub,
          settings: record.settings,
          language: record.language,
          replacement_data: {
            link: Constants.link2CompanyDetail['companies'],
            company_id: record.company_id,
            company_name: record.company_name,
            end_date: DateUtils.formatDate(record.end_date, 'DD/MM/YY HH:mm'),
          },
        });
        recepients.push({
          email: record.contact_email,
          language: record.language,
          replacement_data: {
            admin_name: record.admin_name,
            company_name: record.company_name,
            end_date: DateUtils.formatDate(record.end_date, 'DD/MM/YY HH:mm'),
          }
        });
      }
      p_tasks.push(this.ses_service.sendBulkTemplatedEmail(
        Constants.Email.ExpiryNotification, 
        recepients
      ));
      p_tasks.push(this.notification_service.sendBulkNotifications(
        Constants.Notification.ExpiryNotification,
        identities,
      ));
    }
    if (company_ids?.length) {
      p_tasks.push(this.companyRepository.execute(`
        UPDATE company_licences
        SET status = 3
        WHERE company_id IN (${company_ids.join(',')})
      `));
    }
    if (p_tasks?.length) await Promise.all(p_tasks);
    const finishedAt = new Date();
    console.log(`*** Cronjob: ${this.name} finished at ${finishedAt}. Total in ${(finishedAt.getTime() - startAt.getTime()) / 1000}ms`);
    await this.companyRepository.execute(`SELECT pg_advisory_unlock(${this.lock_key});`);
  }
}