import { Injectable } from '@nestjs/common' import { plainToClass } from 'class-transformer' import { SQSRecord } from 'aws-lambda' import { addHours, endOfHour, startOfHour } from 'date-fns' import { first } from 'lodash' import { MessagingService, ComteleService, AwsService, SmartfitApi, ReporterProcessorService, MailService, } from '../../../services' import { CampaignMessage } from '../../../models' import { CampaignMessageType } from '../../../models/enums' import { Notification } from '../../../services/notification/types' import { BioimpedanceImportationRepository, CampaignMessageRepository } from '../../../repositories' import { PushPayload } from '../../../services/messaging/value-objects' import { LanguageCountryCode } from '../../../utils' import { TranslateNotificationsHelper } from '../i18n' export const NOTIFICATION_REPORT_PROCESS_DELAY_IN_HOURS = 6 export const FLUTTER_ACTION = 'FLUTTER_NOTIFICATION_CLICK' export const BIO_FLUTTER_PAGE = '/home/my-body' export const HOME_FLUTTER_PAGE = '/home' @Injectable() export class Notifications { constructor( private messagingService: MessagingService, private comteleService: ComteleService, private awsService: AwsService, private campaignMessageRepository: CampaignMessageRepository, private smartfitApi: SmartfitApi, private reporterProcessorService: ReporterProcessorService, private mailService: MailService, private bioimpedanceImportationRepository: BioimpedanceImportationRepository, private translator: TranslateNotificationsHelper, ) {} async sendPushNotification(devices: string | Array, payload: PushPayload): Promise { return this.messagingService.sendPushNotification(devices, payload) } async processNotificationReports(): Promise { const date = addHours(new Date(), -NOTIFICATION_REPORT_PROCESS_DELAY_IN_HOURS) const startDateTime = startOfHour(date) const endDateTime = endOfHour(date) await this.reporterProcessorService.processComteleReport(startDateTime, endDateTime) } async sendMessage(message: Notification): Promise { console.log(message) if (message.type == 'bio_importation_sms') { return await this.sendBioSMS(message) } if (message.type == 'sms') { return await this.sendSMS(message) } if (message.type == 'bio_importation_push') { return await this.sendPush(message, BIO_FLUTTER_PAGE) } if (message.type == 'push') { return await this.sendPush(message, message.additional_data.flutter_page || HOME_FLUTTER_PAGE) } if (message.type === 'bio_importation_email') { return await this.sendBioEmail(message) } return false } async deleteMessage(messageRecord: SQSRecord): Promise { await this.awsService.deleteSQSMessage(process.env.NOTIFICATIONS_SQS_URL, messageRecord.receiptHandle) } private async logMessage(message: Notification, messageType: CampaignMessageType): Promise { const msgLog: CampaignMessage = plainToClass(CampaignMessage, { cell_phone: message.additional_data.cell_phone, document_number: message.additional_data.document_number || null, patient_id: message.additional_data.patient_id || null, content: message.msg, type: messageType, campaign_type: message.type, }) return this.campaignMessageRepository.create(msgLog) } private async sendBioEmail({ additional_data }: Notification): Promise { const bioimpedanceImportation = await this.bioimpedanceImportationRepository.get( additional_data.bioimpedance_importation_id, ) const { weight, bioimpedance } = bioimpedanceImportation.toAnthropometry(additional_data) const dynamicTemplateData = { first_name: first(bioimpedanceImportation.name.split(' ')), SMM: bioimpedance.smm, VF: bioimpedance.vfl, ideal_weight: `${bioimpedance.lower_limit_weight}-${bioimpedance.upper_limit_weight} kg`, ideal_SMM: `${bioimpedance.lower_limit_smm}-${bioimpedance.upper_limit_smm} kg`, ideal_VF: bioimpedance.ideal_vfl, BF: bioimpedance.bfm, bio_gender: this.getBioGenderMessage(bioimpedanceImportation.gender, additional_data.country_code), is: bioimpedance.score, weight, } const templateId = this.translator.get('es_DO', 'email_templates.bioimpedance_imported') await this.mailService.send({ templateId, to: additional_data.email, dynamicTemplateData, }) } private async sendPush(message: Notification, page: string): Promise { await this.logMessage(message, CampaignMessageType.PUSH) const msgPush: PushPayload = plainToClass(PushPayload, { notification: { title: message.title, body: message.msg, }, data: { click_action: FLUTTER_ACTION, page, }, }) return await this.messagingService.sendPushNotification(message.additional_data.device_id, msgPush) } private async sendBioSMS(message: Notification): Promise { if (message.additional_data.cell_phone) { return await this.sendSMS(message) } const person = await this.smartfitApi.getPersonByLogin( message.additional_data.document_number ?? message.additional_data.email, ) if (!person) throw new Error('Person not exists') message.additional_data.cell_phone = person.phone return await this.sendSMS(message) } private async sendSMS(message: Notification): Promise { message.controlId = await this.logMessage(message, CampaignMessageType.SMS) if ( (!message.additional_data.cell_phone.startsWith('+') || message.additional_data.cell_phone.startsWith('+55')) && this.comteleService.isEnabled ) { return await this.comteleService.sendSMS({ controlId: message.controlId, message: message.msg, phoneNumber: message.additional_data.cell_phone, }) } return await this.awsService.sendSMS({ message: message.msg, phoneNumber: message.additional_data.cell_phone, }) } private getBioGenderMessage(gender: 'M' | 'F', country_code: LanguageCountryCode): string { switch (country_code) { case LanguageCountryCode.ES_DO: case LanguageCountryCode.ES_MX: case LanguageCountryCode.ES_EC: return gender === 'M' ? 'de los hombres' : 'de las mujeres' case LanguageCountryCode.PT_BR: default: return gender === 'M' ? 'dos homens' : 'das mulheres' } } }