UNPKG

@criapix/saas-assinaturas-client

Version:

SDK JavaScript/TypeScript para o AssinaturasService - Sistema de gestão de assinaturas SaaS com processamento de pagamentos de faturas (cartão, PIX, débito), gerenciamento de métodos de pagamento, pagamentos recorrentes e análise de falhas de pagamento

597 lines (529 loc) 19.9 kB
import axios, { AxiosInstance, AxiosError } from 'axios'; import { normalizeCardExpiryDate } from '../utils/cardExpiryDateValidator'; import type { PaginatedResponse, CreateCustomerRequest, CustomerResponse, CreateOneTimePaymentRequest, CreateRecurringPaymentRequest, ProcessPaymentRequest, CancelPaymentRequest, PaymentListQuery, PaymentResponse, CreatePaymentAccountRequest, PaymentAccountResponse, SubscriptionStatusResponse, SimpleActiveStatusResponse, PaymentMethodInfoResponse, ProcessInvoicePaymentResponse, ProcessFirstPaymentRequest, ProcessRecurringPaymentRequest, ProcessPixPaymentRequest, ProcessDebitPaymentRequest, SubscriptionPlanResponse, CreateSubscriptionPlanRequest, UpdateSubscriptionPlanRequest, SubscriptionPlanFilterRequest, SubscriptionResponse, CreateSubscriptionRequest, UpdateSubscriptionRequest, UpdatePaymentMethodRequest, ActivateSubscriptionWithPaymentRequest, SubscriptionActivationResponse, SubscriptionFilterRequest, InvoiceResponse, InvoiceStatisticsResponse, GenerateInvoiceRequest, InvoiceFilterRequest, UpdateInvoiceStatusRequest, GenerateBatchInvoicesRequest, BatchInvoiceResponse, SubscriptionAccessResponse, CheckAccessBatchRequest, CustomerAccessBatchItem, } from '../types'; export class AssinaturasServiceClient { private client: AxiosInstance; private authToken: string | null = null; constructor(baseURL: string) { this.client = axios.create({ baseURL, timeout: 30000, headers: { 'Content-Type': 'application/json', }, }); // Interceptor para adicionar token de autenticação this.client.interceptors.request.use((config) => { if (this.authToken) { config.headers.Authorization = `Bearer ${this.authToken}`; } return config; }); // Interceptor para tratamento de erros this.client.interceptors.response.use( (response) => response, (error: AxiosError) => { if (error.response?.status === 404) { // Retornar null para 404 em alguns casos específicos return Promise.resolve({ data: null }); } return Promise.reject(error); } ); } /** * Define o token de autenticação JWT */ public setAuthorizationToken(token: string): void { this.authToken = token; } // ==================== Customers ==================== /** * Cria um novo cliente */ async createCustomer(request: CreateCustomerRequest): Promise<CustomerResponse> { const { data } = await this.client.post<CustomerResponse>('/Customers', request); return data; } /** * Busca um cliente por ID * @returns O cliente encontrado ou null se não existir */ async getCustomer(id: string): Promise<CustomerResponse | null> { const { data } = await this.client.get<CustomerResponse>(`/Customers/${id}`); return data; } // ==================== Subscription Plans ==================== /** * Cria um novo plano de assinatura */ async createSubscriptionPlan(request: CreateSubscriptionPlanRequest): Promise<SubscriptionPlanResponse> { const { data } = await this.client.post<SubscriptionPlanResponse>('/SubscriptionPlans', request); return data; } /** * Busca um plano de assinatura por ID * @returns O plano encontrado ou null se não existir */ async getSubscriptionPlan(id: string): Promise<SubscriptionPlanResponse | null> { const { data } = await this.client.get<SubscriptionPlanResponse>(`/SubscriptionPlans/${id}`); return data; } /** * Lista planos de assinatura com filtros opcionais */ async listSubscriptionPlans( filter?: SubscriptionPlanFilterRequest ): Promise<PaginatedResponse<SubscriptionPlanResponse>> { const params: Record<string, string | number | boolean> = { page: filter?.page ?? 1, pageSize: filter?.pageSize ?? 10, }; if (filter?.name) params.name = filter.name; if (filter?.isActive !== undefined) params.isActive = filter.isActive; if (filter?.isDefault !== undefined) params.isDefault = filter.isDefault; const { data } = await this.client.get<PaginatedResponse<SubscriptionPlanResponse>>( '/SubscriptionPlans', { params } ); return data; } /** * Atualiza um plano de assinatura existente */ async updateSubscriptionPlan( id: string, request: UpdateSubscriptionPlanRequest ): Promise<SubscriptionPlanResponse> { const { data } = await this.client.put<SubscriptionPlanResponse>(`/SubscriptionPlans/${id}`, request); return data; } /** * Deleta um plano de assinatura */ async deleteSubscriptionPlan(id: string): Promise<void> { await this.client.delete(`/SubscriptionPlans/${id}`); } // ==================== Subscriptions ==================== /** * Cria uma nova assinatura */ async createSubscription(request: CreateSubscriptionRequest): Promise<SubscriptionResponse> { const { data } = await this.client.post<SubscriptionResponse>('/Subscriptions', request); return data; } /** * Busca uma assinatura por ID * @returns A assinatura encontrada ou null se não existir */ async getSubscription(id: string): Promise<SubscriptionResponse | null> { const { data } = await this.client.get<SubscriptionResponse>(`/Subscriptions/${id}`); return data; } /** * Lista assinaturas com filtros opcionais */ async listSubscriptions(filter?: SubscriptionFilterRequest): Promise<PaginatedResponse<SubscriptionResponse>> { const params: Record<string, string | number> = { page: filter?.page ?? 1, pageSize: filter?.pageSize ?? 10, }; if (filter?.customerId) params.customerId = filter.customerId; if (filter?.subscriptionPlanId) params.subscriptionPlanId = filter.subscriptionPlanId; if (filter?.status !== undefined) params.status = filter.status; const { data } = await this.client.get<PaginatedResponse<SubscriptionResponse>>('/Subscriptions', { params, }); return data; } /** * Atualiza uma assinatura existente */ async updateSubscription(id: string, request: UpdateSubscriptionRequest): Promise<SubscriptionResponse> { const { data } = await this.client.put<SubscriptionResponse>(`/Subscriptions/${id}`, request); return data; } /** * Cancela uma assinatura */ async cancelSubscription(id: string, cancellationReason?: string): Promise<SubscriptionResponse> { const { data } = await this.client.post<SubscriptionResponse>(`/Subscriptions/${id}/cancel`, { cancellationReason, }); return data; } /** * Ativa uma assinatura com primeiro pagamento após período de trial * Este endpoint encontra a fatura pendente atual e processa o pagamento * @param subscriptionId - ID da assinatura * @param request - Requisição com detalhes do cartão para ativação * @returns Resultado da ativação da assinatura */ async activateSubscriptionWithPayment( subscriptionId: string, request: ActivateSubscriptionWithPaymentRequest ): Promise<SubscriptionActivationResponse> { const { data } = await this.client.post<SubscriptionActivationResponse>( `/Subscriptions/${subscriptionId}/activate-with-payment`, request ); return data; } /** * Atualiza o método de pagamento de uma assinatura * Pode opcionalmente processar um pagamento de fatura pendente ao atualizar o método * @param subscriptionId - ID da assinatura * @param request - Requisição com novos detalhes do cartão * @returns Resultado do processamento do pagamento (se fatura fornecida) ou confirmação de sucesso */ async updatePaymentMethod( subscriptionId: string, request: UpdatePaymentMethodRequest ): Promise<ProcessInvoicePaymentResponse> { // Normalize cardExpiryDate to ISO 8601 format before sending to API const normalizedRequest = { ...request, cardExpiryDate: normalizeCardExpiryDate(request.cardExpiryDate), }; const { data } = await this.client.put<ProcessInvoicePaymentResponse>( `/Subscriptions/${subscriptionId}/payment-method`, normalizedRequest ); return data; } // ==================== Invoices ==================== /** * Busca uma fatura por ID * @returns A fatura encontrada ou null se não existir */ async getInvoice(id: string): Promise<InvoiceResponse | null> { const { data } = await this.client.get<InvoiceResponse>(`/Invoices/${id}`); return data; } /** * Lista faturas com filtros opcionais */ async listInvoices(filter?: InvoiceFilterRequest): Promise<PaginatedResponse<InvoiceResponse>> { const params: Record<string, string | number> = { page: filter?.page ?? 1, pageSize: filter?.pageSize ?? 10, }; if (filter?.subscriptionId) params.subscriptionId = filter.subscriptionId; if (filter?.status !== undefined) params.status = filter.status; if (filter?.dueDateFrom) params.dueDateFrom = filter.dueDateFrom; if (filter?.dueDateTo) params.dueDateTo = filter.dueDateTo; const { data } = await this.client.get<PaginatedResponse<InvoiceResponse>>('/Invoices', { params }); return data; } /** * Gera uma nova fatura */ async generateInvoice(request: GenerateInvoiceRequest): Promise<InvoiceResponse> { const { data } = await this.client.post<InvoiceResponse>('/Invoices/generate', request); return data; } /** * Atualiza o status de uma fatura */ async updateInvoiceStatus(id: string, request: UpdateInvoiceStatusRequest): Promise<InvoiceResponse> { const { data } = await this.client.put<InvoiceResponse>(`/Invoices/${id}/status`, request); return data; } /** * Gera faturas em lote para todas as assinaturas ativas */ async generateBatchInvoices(request: GenerateBatchInvoicesRequest): Promise<BatchInvoiceResponse> { const { data } = await this.client.post<BatchInvoiceResponse>('/Invoices/generate-batch', request); return data; } /** * Obtém estatísticas agregadas de faturas * @param startDate - Data inicial do filtro (opcional) * @param endDate - Data final do filtro (opcional) * @param condominiumId - ID do condomínio para filtrar (opcional) * @returns Estatísticas das faturas */ async getInvoiceStatistics( startDate?: string, endDate?: string, condominiumId?: string ): Promise<InvoiceStatisticsResponse> { const params: Record<string, string> = {}; if (startDate) params.startDate = startDate; if (endDate) params.endDate = endDate; if (condominiumId) params.condominiumId = condominiumId; const { data } = await this.client.get<InvoiceStatisticsResponse>('/Invoices/statistics', { params }); return data; } // ==================== Invoice Payments ==================== /** * Processa o primeiro pagamento após período de trial com tokenização de cartão * Armazena o método de pagamento para pagamentos recorrentes futuros * @param invoiceId - ID da fatura * @param request - Requisição com token do cartão e informações do cliente * @returns Resultado do processamento do pagamento */ async processFirstPayment( invoiceId: string, request: ProcessFirstPaymentRequest ): Promise<ProcessInvoicePaymentResponse> { // Normalize cardExpiryDate to ISO 8601 format before sending to API const normalizedRequest = { ...request, cardExpiryDate: normalizeCardExpiryDate(request.cardExpiryDate), }; const { data } = await this.client.post<ProcessInvoicePaymentResponse>( `/Invoices/${invoiceId}/process-first-payment`, normalizedRequest ); return data; } /** * Processa pagamento recorrente mensal usando método de pagamento armazenado * @param invoiceId - ID da fatura * @param request - Requisição de pagamento recorrente (vazio, apenas invoiceId na URL) * @returns Resultado do processamento do pagamento */ async processRecurringPayment( invoiceId: string, request: ProcessRecurringPaymentRequest = {} ): Promise<ProcessInvoicePaymentResponse> { const { data } = await this.client.post<ProcessInvoicePaymentResponse>( `/Invoices/${invoiceId}/process-recurring-payment`, request ); return data; } /** * Processa pagamento PIX * Gera QR Code para pagamento instantâneo * @param invoiceId - ID da fatura * @param request - Requisição de pagamento PIX com informações do cliente * @returns Resultado do processamento com QR Code */ async processPixPayment( invoiceId: string, request: ProcessPixPaymentRequest ): Promise<ProcessInvoicePaymentResponse> { const { data } = await this.client.post<ProcessInvoicePaymentResponse>( `/Invoices/${invoiceId}/process-pix-payment`, request ); return data; } /** * Processa pagamento com cartão de débito * Pagamento imediato, sem capacidade de recorrência * @param invoiceId - ID da fatura * @param request - Requisição de pagamento com token do cartão de débito e informações do cliente * @returns Resultado do processamento do pagamento */ async processDebitPayment( invoiceId: string, request: ProcessDebitPaymentRequest ): Promise<ProcessInvoicePaymentResponse> { // Normalize cardExpiryDate to ISO 8601 format before sending to API const normalizedRequest = { ...request, cardExpiryDate: normalizeCardExpiryDate(request.cardExpiryDate), }; const { data } = await this.client.post<ProcessInvoicePaymentResponse>( `/Invoices/${invoiceId}/process-debit-payment`, normalizedRequest ); return data; } // ==================== Subscription Status ==================== /** * Obtém o status completo da assinatura de um cliente * @returns Status completo ou null se não encontrado */ async getSubscriptionStatus(customerId: string): Promise<SubscriptionStatusResponse | null> { const { data } = await this.client.get<SubscriptionStatusResponse>(`/subscription-status/${customerId}`); return data; } /** * Verifica se o cliente está ativo (status simples) */ async getSimpleStatus(customerId: string): Promise<SimpleActiveStatusResponse> { const { data } = await this.client.get<SimpleActiveStatusResponse>( `/subscription-status/${customerId}/is-active` ); return data; } /** * Verifica se o cliente está inadimplente */ async isDelinquent(customerId: string): Promise<boolean> { const { data } = await this.client.get<boolean>(`/subscription-status/${customerId}/is-delinquent`); return data; } // ==================== Payments ==================== /** * Cria um pagamento avulso (one-time) */ async createOneTimePayment(request: CreateOneTimePaymentRequest): Promise<PaymentResponse> { const { data } = await this.client.post<PaymentResponse>('/Payments/one-time', request); return data; } /** * Cria um pagamento recorrente */ async createRecurringPayment(request: CreateRecurringPaymentRequest): Promise<PaymentResponse> { const { data } = await this.client.post<PaymentResponse>('/Payments/recurring', request); return data; } /** * Processa um pagamento com token de cartão */ async processPayment(paymentId: string, request: ProcessPaymentRequest): Promise<PaymentResponse> { const { data } = await this.client.post<PaymentResponse>(`/Payments/${paymentId}/process`, request); return data; } /** * Busca um pagamento por ID * @returns O pagamento encontrado ou null se não existir */ async getPayment(paymentId: string): Promise<PaymentResponse | null> { const { data } = await this.client.get<PaymentResponse>(`/Payments/${paymentId}`); return data; } /** * Lista pagamentos com filtros opcionais * @param query - Filtros de busca (customerId, subscriptionId, status) */ async listPayments(query?: PaymentListQuery & { customerId?: string; subscriptionId?: string }): Promise<PaymentResponse[]> { const params: Record<string, string | number> = {}; if (query?.customerId) params.customerId = query.customerId; if (query?.subscriptionId) params.subscriptionId = query.subscriptionId; if (query?.status !== undefined) params.status = query.status; if (query?.page) params.page = query.page; if (query?.pageSize) params.pageSize = query.pageSize; const { data } = await this.client.get<PaymentResponse[]>('/Payments', { params }); return data; } /** * Obtém o método de pagamento de uma assinatura * @param subscriptionId - ID da assinatura * @returns Informações do método de pagamento ou null se não existir */ async getPaymentMethod(subscriptionId: string): Promise<PaymentMethodInfoResponse | null> { const { data } = await this.client.get<PaymentMethodInfoResponse>(`/Subscriptions/${subscriptionId}/payment-method`); return data; } /** * Cancela um pagamento recorrente */ async cancelPayment(paymentId: string, request?: CancelPaymentRequest): Promise<PaymentResponse> { const { data } = await this.client.delete<PaymentResponse>(`/Payments/${paymentId}`, { data: request }); return data; } // ==================== Payment Accounts ==================== /** * Cria uma nova conta de pagamento (credenciais Mercado Pago) */ async createPaymentAccount(request: CreatePaymentAccountRequest): Promise<PaymentAccountResponse> { const { data } = await this.client.post<PaymentAccountResponse>('/PaymentAccounts', request); return data; } /** * Busca uma conta de pagamento por ID * @returns A conta encontrada ou null se não existir */ async getPaymentAccount(accountId: string): Promise<PaymentAccountResponse | null> { const { data } = await this.client.get<PaymentAccountResponse>(`/PaymentAccounts/${accountId}`); return data; } /** * Busca a conta de pagamento padrão * @returns A conta padrão ou null se não existir */ async getDefaultPaymentAccount(): Promise<PaymentAccountResponse | null> { const { data } = await this.client.get<PaymentAccountResponse>('/PaymentAccounts/default'); return data; } /** * Lista todas as contas de pagamento */ async listPaymentAccounts(): Promise<PaymentAccountResponse[]> { const { data } = await this.client.get<PaymentAccountResponse[]>('/PaymentAccounts'); return data; } // ==================== Subscription Access ==================== /** * Verifica se um cliente tem acesso ao sistema * @param customerId - ID do cliente * @returns Informações de acesso do cliente */ async checkAccess(customerId: string): Promise<SubscriptionAccessResponse> { const { data } = await this.client.get<SubscriptionAccessResponse>( `/SubscriptionAccess/check-access`, { params: { customerId } } ); return data; } /** * Verifica acesso para um cliente específico (rota alternativa) * @param customerId - ID do cliente * @returns Informações de acesso do cliente */ async checkAccessByCustomer(customerId: string): Promise<SubscriptionAccessResponse> { const { data } = await this.client.get<SubscriptionAccessResponse>( `/SubscriptionAccess/customers/${customerId}/access` ); return data; } /** * Verifica acesso para múltiplos clientes em uma única requisição * @param request - Lista de IDs de clientes (máx 100) * @returns Lista de status de acesso para cada cliente */ async checkAccessBatch(request: CheckAccessBatchRequest): Promise<CustomerAccessBatchItem[]> { const { data } = await this.client.post<CustomerAccessBatchItem[]>( '/SubscriptionAccess/check-access-batch', request ); return data; } }