import { Injectable } from '@nestjs/common' import { classToPlain } from 'class-transformer' import { isEmpty, uniqBy } from 'lodash' import { PaymentProviders } from '../models' import { Plan } from '../models/plan.model' import { HttpService } from '../services/http' import { CountryCode } from '../utils' import { BaseRepository } from './base.repository' const INSERT = ` mutation insertPlan($plan: plan_insert_input!) { insert_plan_one(object: $plan) { id } } ` const FIND_ATTRIBUTES = ` id enabled interval name order trial_interval trial_value visible omie_service_id complete payment_providers { provider code smartfit_id from_amount amount country_code } ` const FEATURES_ATTRIBUTES = ` feature country_code provider interval quantity ` const FIND_BY_ADDON_ID = ` query plan($addonId: String!) { plans: plan(where: {payment_providers: {smartfit_id: {_eq: $addonId}}}) { ${FIND_ATTRIBUTES} features { ${FEATURES_ATTRIBUTES} } } } ` const FIND_BY_ADDON_CODE = ` query plan($provider: payment_provider_enum!, $addonCode: String!) { plans: plan(where: {payment_providers: {provider: {_eq: $provider}, code: {_eq: $addonCode}}}) { ${FIND_ATTRIBUTES} } } ` const FIND_ENABLED_VISIBLE = ` query plan { plans: plan(where: {enabled: {_eq: true}, visible: {_eq: true}}, order_by: {order: asc}) { ${FIND_ATTRIBUTES} } } ` const FIND_ENABLED_VISIBLE_COMPLETE = ` query plan { plans: plan(where: {enabled: {_eq: true}, visible: {_eq: true}, complete: {_eq: true}}, order_by: {order: asc}) { ${FIND_ATTRIBUTES} } } ` const FIND_ENABLED = ` query plan { plans: plan(where: {enabled: {_eq: true}}, order_by: {order: asc}) { ${FIND_ATTRIBUTES} } } ` const FIND_ENABLED_UPGRADEABLES_FROM_PLAN_ID = ` query plan($plan_id: uuid) { plans_upgradeables(where: {plan_id_from: {_eq: $plan_id}, plan_to: {enabled: {_eq: true}}}, order_by: {plan_to: {order: asc}}) { plan_to { ${FIND_ATTRIBUTES} } } } ` const FIND_ENABLED_WITH_TELECONSULTATIONS = ` query planEnabledWithTeleconsultations { plan(where: {enabled: {_eq: true}, features: {feature: {_eq: "teleconsultation"}, quantity: {_gte: 1}}}) { id features { ${FEATURES_ATTRIBUTES} } } } ` const GET = ` query plan($id: uuid!) { plans: plan(where: {id: {_eq: $id}}, limit: 1) { ${FIND_ATTRIBUTES} } } ` const GET_WITH_FEATURES = ` query plan($id: uuid!, $countryCode: String!, $provider: payment_provider_enum!) { plans: plan(where: {id: {_eq: $id}}, limit: 1) { ${FIND_ATTRIBUTES} features(where: {country_code: {_eq: $countryCode}, provider: {_eq: $provider}}) { ${FEATURES_ATTRIBUTES} } } } ` const FIND_VISIBLE_ENABLED_WITH_FEATURES = ` query plan($countryCode: String!, $provider: payment_provider_enum!) { plans: plan(where: {payment_providers: {provider: {_eq: $provider}, country_code: {_eq: $countryCode}}, enabled: {_eq: true}, visible: {_eq: true}}) { ${FIND_ATTRIBUTES} features(where: {country_code: {_eq: $countryCode}, provider: {_eq: $provider}}) { ${FEATURES_ATTRIBUTES} } } } ` @Injectable() export class PlanRepository extends BaseRepository { constructor(protected readonly httpService: HttpService) { super(httpService, 'plan') } async create(plan: Partial): Promise { const qv = { plan: classToPlain(plan) } const { data } = await this.fetchGraphQL({ body: { query: INSERT, variables: qv }, }) return data.insert_plan_one.id } async findByAddonId(addonId: string): Promise { const { data } = await this.fetchGraphQL({ body: { query: FIND_BY_ADDON_ID, variables: { addonId } }, throwErrors: false, }) return isEmpty(data) || isEmpty(data.plans) ? null : Plan.toInstance(data.plans.shift()) } async findByAddonCode(addonCode: string, provider: string): Promise { const { data } = await this.fetchGraphQL({ body: { query: FIND_BY_ADDON_CODE, variables: { addonCode, provider } }, throwErrors: false, }) return isEmpty(data) || isEmpty(data.plans) ? null : Plan.toInstance(data.plans.shift()) } async findEnabledAndVisible(options?: { language?: string; complete?: boolean }): Promise> { const { data } = await this.fetchGraphQL({ body: { query: options.complete ? FIND_ENABLED_VISIBLE_COMPLETE : FIND_ENABLED_VISIBLE }, ...options, throwErrors: false, }) return !isEmpty(data) && data.plans.map(plan => Plan.toInstance(plan)) } async findEnabledWithTeleconsultations(): Promise> { const { data } = await this.fetchGraphQL({ body: { query: FIND_ENABLED_WITH_TELECONSULTATIONS }, throwErrors: false, }) return !isEmpty(data) && data.plan.map((plan: Plan) => Plan.toInstance(plan)) } async findEnabled(options?: { language?: string }): Promise> { const { data } = await this.fetchGraphQL({ body: { query: FIND_ENABLED }, ...options, throwErrors: false, }) return !isEmpty(data) && data.plans.map(plan => Plan.toInstance(plan)) } async findAvailableWithFeatures({ countryCode, provider, }: { countryCode: CountryCode provider: PaymentProviders }): Promise> { const { data } = await this.fetchGraphQL({ body: { query: FIND_VISIBLE_ENABLED_WITH_FEATURES, variables: { countryCode, provider } }, language: countryCode, }) return !isEmpty(data) && data.plans.map((plan: Partial) => Plan.toInstance(plan)) } async findUpgradeablePlansByPlanId(plan_id: string, options?: { language?: string }): Promise> { const { data } = await this.fetchGraphQL({ body: { query: FIND_ENABLED_UPGRADEABLES_FROM_PLAN_ID, variables: { plan_id } }, ...options, throwErrors: false, }) return ( (!isEmpty(data) && uniqBy( data.plans_upgradeables?.map((planUpgradeable: { plan_to: Plan }) => Plan.toInstance(planUpgradeable.plan_to), ), plan => plan.id, )) || [] ) } async get(id: string, options?: { language?: string }): Promise { const { data } = await this.fetchGraphQL({ body: { query: GET, variables: { id } }, ...options, }) return isEmpty(data) || isEmpty(data.plans) ? null : Plan.toInstance(data.plans.shift()) } async getWithFeatures(id: string, countryCode: CountryCode, provider: PaymentProviders): Promise { const { data } = await this.fetchGraphQL({ body: { query: GET_WITH_FEATURES, variables: { id, countryCode, provider } }, language: countryCode, }) return isEmpty(data) || isEmpty(data.plans) ? null : Plan.toInstance(data.plans.shift()) } }