import { Injectable } from '@nestjs/common' import { isEmpty } from 'lodash' import { BadAuthenticationError, BusinessExceptionError, NotFoundError } from '../../../errors' import { PaymentProviders } from '../../../models' import { PatientRepository, PlanRepository, SmartfitUnitRepository } from '../../../repositories' import { AccountService, SubscriptionService } from '../../../services' import { CountryCode } from '../../../utils' import { maskEmail } from '../../../utils/string/mask_email' import { ConfirmSubscriptionParams } from '../controllers/params' import { TotemPlan } from '../models' import { ConfirmSubscriptionResponse } from '../type' @Injectable() export class Plans { private get paymentProvider(): PaymentProviders { return globalThis.secret.n2b_payments?.enable || false ? PaymentProviders.N2B : PaymentProviders.SMARTFIT } constructor( private readonly patientRepository: PatientRepository, private readonly accountService: AccountService, private readonly subscriptionService: SubscriptionService, private readonly planRepository: PlanRepository, private readonly smartfitUnitRepository: SmartfitUnitRepository, ) {} async getPlans({ countryCode }: { countryCode: CountryCode }): Promise> { const plans = await this.planRepository.findAvailableWithFeatures({ countryCode, provider: this.paymentProvider, }) return plans.map(plan => { return TotemPlan.fromPlan(plan, { provider: this.paymentProvider, countryCode }) }) } async subscribe(login: string): Promise { const patient = await this.accountService.createOrUpdatePatient(login) if (!patient) throw new NotFoundError('Patient not found') if (patient.subscriber) throw new BusinessExceptionError('Patient already subscribed') return maskEmail(patient.email) } async confirmAndSubscribe({ login, email, plan_id, smartfit_unit_id, }: ConfirmSubscriptionParams): Promise { const patient = await this.patientRepository.findByLogin(login) if (patient.email !== email) throw new BadAuthenticationError('Invalid confirmation') if (patient.subscriber) return { confirmed: true, patient_name: patient.name } const plan = await this.planRepository.get(plan_id) if (isEmpty(plan)) throw new NotFoundError('Plan not found') const subscription = await this.subscriptionService.subscribe({ patient, plan, paymentProvider: { provider: this.paymentProvider }, data: { sales_channel: 'measurement_totem', origin: 'n2b', ...(smartfit_unit_id ? { smartfit_unit_id } : {}), }, }) return { confirmed: !!subscription, patient_name: patient.name } } }