import { Injectable } from '@nestjs/common' import { classToPlain } from 'class-transformer' import { first, isEmpty, last } from 'lodash' import { SubscriptionInstallment } from '../models' import { HttpService } from '../services/http' import { BaseRepository } from './base.repository' const ATTRIBUTES = ` id subscription_id installment amount paid_at due_date created_at updated_at omie_os_code omie_is_invoiced ` const INSERT = ` mutation insertSubscriptionInstallment($subscriptionInstallments: [subscription_installment_insert_input!]!) { insert_subscription_installment(objects: $subscriptionInstallments) { affected_rows returning { ${ATTRIBUTES} } } } ` const GET = ` query subscriptionInstallment($id: uuid!) { subscription_installment(where: {id: {_eq: $id}}) { ${ATTRIBUTES} } } ` const FIND_BY_SUBSCRIPTION = ` query subscriptionInstallment($subscriptionId: uuid!) { subscription_installment(where: {subscription_id: {_eq: $subscriptionId}}, order_by: {installment: asc, created_at: asc}) { ${ATTRIBUTES} } } ` const FIND_OVERDUE_BY_SUBSCRIPTION = ` query overdueSubscriptionInstallment($subscriptionId: uuid!) { subscription_installment(where: {subscription_id: {_eq: $subscriptionId}, paid_at: {_is_null: true}, due_date: {_lte: "now()"}}, order_by: {installment: asc, created_at: asc}, limit: 1) { ${ATTRIBUTES} } } ` const FIND_BY_SUBSCRIPTION_AND_NUMBER = ` query subscriptionInstallmentByNumber($subscriptionId: uuid!, $number: Int!) { subscription_installment(where: {subscription_id: {_eq: $subscriptionId}, installment: {_eq: $number}}, limit: 1) { ${ATTRIBUTES} } } ` const TOTAL_BY_SUBSCRIPTION = ` query subscriptionInstallment($subscriptionId: uuid!) { total: subscription_installment_aggregate(where: {subscription_id: {_eq: $subscriptionId}}) { aggregate { count } } } ` @Injectable() export class SubscriptionInstallmentRepository extends BaseRepository { constructor(protected readonly httpService: HttpService) { super(httpService, 'subscription_installment') } async create(subscriptionInstallments: Array): Promise> { const qv = { subscriptionInstallments: subscriptionInstallments.map(subscriptionInstallment => classToPlain(subscriptionInstallment), ), } const { errors, data } = await this.fetchGraphQL({ body: { query: INSERT, variables: qv }, throwErrors: false, }) if (errors) throw new Error(errors.shift()?.message) return data.insert_subscription_installment.returning.map((value: SubscriptionInstallment) => SubscriptionInstallment.toInstance(value), ) } async get(id: string): Promise { const { data, errors } = await this.fetchGraphQL({ body: { query: GET, variables: { id } }, throwErrors: false, }) if (errors) throw new Error(errors.shift()?.message) return isEmpty(data.subscription_installment) ? null : SubscriptionInstallment.toInstance(data.subscription_installment[0]) } async findBySubscription(subscriptionId: string): Promise { const { data, errors } = await this.fetchGraphQL({ body: { query: FIND_BY_SUBSCRIPTION, variables: { subscriptionId } }, throwErrors: false, }) if (errors) throw new Error(errors.shift()?.message) return isEmpty(data.subscription_installment) ? [] : data.subscription_installment.map((value: SubscriptionInstallment) => SubscriptionInstallment.toInstance(value)) } async findBySubscriptionAndNumber(subscriptionId: string, number: number): Promise { const { data, errors } = await this.fetchGraphQL({ body: { query: FIND_BY_SUBSCRIPTION_AND_NUMBER, variables: { subscriptionId, number } }, throwErrors: false, }) if (errors) throw new Error(errors.shift()?.message) return isEmpty(data.subscription_installment) ? null : SubscriptionInstallment.toInstance(first(data.subscription_installment)) } async findOverdueBySubscription(subscriptionId: string): Promise { const { data, errors } = await this.fetchGraphQL({ body: { query: FIND_OVERDUE_BY_SUBSCRIPTION, variables: { subscriptionId } }, throwErrors: false, }) if (errors) throw new Error(errors.shift()?.message) return isEmpty(data.subscription_installment) ? null : SubscriptionInstallment.toInstance(last(data.subscription_installment)) } async getTotalBySubscription(subscriptionId: string): Promise { const { data, errors } = await this.fetchGraphQL({ body: { query: TOTAL_BY_SUBSCRIPTION, variables: { subscriptionId } }, throwErrors: false, }) if (errors) throw new Error(errors.shift()?.message) return data.total?.aggregate?.count || 0 } async scheduleServiceOrderInvoicing(installment: SubscriptionInstallment, date: Date): Promise { const { data } = await this.createScheduledEvent( '{{ACTIONS_HANDLER_URL}}/contract/emit_service_order', date, `Installment ${installment.installment} from subscription ${installment.subscription_id} service order invoicing`, installment.toPlain(), [ { name: 'Authorization', value: `Bearer ${globalThis.secret.hasura_graphql.access_token}`, }, ], { retriesQuantity: 3, retryInterval: 3600, }, ) return data } }