refractor code,
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
import { PLAN_PRICES } from '@rentaldrivego/types'
|
||||
import { prisma } from '../../lib/prisma'
|
||||
import { ValidationError } from '../../http/errors'
|
||||
import * as amanpay from '../../services/amanpayService'
|
||||
import * as paypal from '../../services/paypalService'
|
||||
import * as repo from './subscription.repo'
|
||||
|
||||
export function addPeriod(date: Date, period: string): Date {
|
||||
const d = new Date(date)
|
||||
period === 'ANNUAL' ? d.setFullYear(d.getFullYear() + 1) : d.setMonth(d.getMonth() + 1)
|
||||
return d
|
||||
}
|
||||
|
||||
export function getPlans() {
|
||||
return PLAN_PRICES
|
||||
}
|
||||
|
||||
export function getProviders() {
|
||||
return { amanpay: amanpay.isConfigured(), paypal: paypal.isConfigured() }
|
||||
}
|
||||
|
||||
export function getSubscription(companyId: string) {
|
||||
return repo.findByCompany(companyId)
|
||||
}
|
||||
|
||||
export function getInvoices(companyId: string) {
|
||||
return repo.findInvoices(companyId)
|
||||
}
|
||||
|
||||
export async function handleAmanpayWebhook(event: any) {
|
||||
const transactionId = event.transaction_id ?? event.id
|
||||
const status = event.status?.toUpperCase()
|
||||
if (status === 'PAID' || status === 'SUCCEEDED') {
|
||||
const invoice = await repo.findInvoiceByAmanpay(transactionId)
|
||||
if (invoice) {
|
||||
await repo.markInvoicePaid(invoice.id)
|
||||
await repo.activateSubscription(invoice.subscriptionId, addPeriod(new Date(), invoice.subscription.billingPeriod))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function handlePaypalWebhook(event: any) {
|
||||
if (event.event_type === 'PAYMENT.CAPTURE.COMPLETED') {
|
||||
const captureId = event.resource?.id as string
|
||||
const invoice = await repo.findInvoiceByPaypal(captureId)
|
||||
if (invoice) {
|
||||
await repo.markInvoicePaid(invoice.id)
|
||||
await repo.activateSubscription(invoice.subscriptionId, addPeriod(new Date(), invoice.subscription.billingPeriod))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkout(companyId: string, body: {
|
||||
plan: 'STARTER' | 'GROWTH' | 'PRO'; billingPeriod: 'MONTHLY' | 'ANNUAL'
|
||||
currency: 'MAD' | 'USD' | 'EUR'; provider: 'AMANPAY' | 'PAYPAL'
|
||||
successUrl: string; failureUrl: string
|
||||
}) {
|
||||
const prices = PLAN_PRICES[body.plan]?.[body.billingPeriod]
|
||||
if (!prices) throw new ValidationError('Invalid plan or billing period')
|
||||
const amount = (prices as any)[body.currency]
|
||||
if (!amount) throw new ValidationError('Currency not supported for this plan')
|
||||
|
||||
const company = await prisma.company.findUniqueOrThrow({ where: { id: companyId } })
|
||||
const subscription = await repo.findOrCreateSubscription(companyId, body.plan, body.billingPeriod, body.currency)
|
||||
|
||||
const orderId = `sub-${companyId}-${Date.now()}`
|
||||
const description = `${body.plan} plan — ${body.billingPeriod}`
|
||||
const webhookBase = process.env.API_URL ?? 'http://localhost:4000'
|
||||
|
||||
let checkoutUrl: string
|
||||
let amanpayTransactionId: string | null = null
|
||||
let paypalCaptureId: string | null = null
|
||||
|
||||
if (body.provider === 'AMANPAY') {
|
||||
if (!amanpay.isConfigured()) throw new ValidationError('AmanPay is not configured on this platform')
|
||||
const result = await amanpay.createCheckout({
|
||||
amount, currency: body.currency, orderId, description,
|
||||
customerEmail: company.email, customerName: company.name,
|
||||
successUrl: body.successUrl, failureUrl: body.failureUrl,
|
||||
webhookUrl: `${webhookBase}/api/v1/subscriptions/webhooks/amanpay`,
|
||||
})
|
||||
checkoutUrl = result.checkoutUrl
|
||||
amanpayTransactionId = result.transactionId
|
||||
} else {
|
||||
if (!paypal.isConfigured()) throw new ValidationError('PayPal is not configured on this platform')
|
||||
const result = await paypal.createOrder({ amount, currency: body.currency, orderId, description, returnUrl: body.successUrl, cancelUrl: body.failureUrl })
|
||||
checkoutUrl = result.approveUrl
|
||||
paypalCaptureId = result.orderId
|
||||
}
|
||||
|
||||
const invoice = await repo.createInvoice({ companyId, subscriptionId: subscription.id, amount, currency: body.currency, paymentProvider: body.provider, amanpayTransactionId, paypalCaptureId })
|
||||
return { invoice, checkoutUrl }
|
||||
}
|
||||
|
||||
export async function capturePaypal(companyId: string, paypalOrderId: string) {
|
||||
const invoice = await repo.findInvoiceByPaypalForCompany(paypalOrderId, companyId)
|
||||
const capture = await paypal.captureOrder(paypalOrderId) as Record<string, any>
|
||||
const captureId = capture.purchase_units?.[0]?.payments?.captures?.[0]?.id ?? paypalOrderId
|
||||
await repo.updateInvoicePaypal(invoice.id, captureId)
|
||||
await repo.activateSubscription(invoice.subscriptionId, addPeriod(new Date(), invoice.subscription.billingPeriod))
|
||||
return { success: true }
|
||||
}
|
||||
|
||||
export function changePlan(companyId: string, data: { plan: any; billingPeriod: any; currency: string }) {
|
||||
return repo.updatePlan(companyId, data)
|
||||
}
|
||||
|
||||
export function cancel(companyId: string) {
|
||||
return repo.setCancelAtPeriodEnd(companyId, true)
|
||||
}
|
||||
|
||||
export function resume(companyId: string) {
|
||||
return repo.setCancelAtPeriodEnd(companyId, false)
|
||||
}
|
||||
Reference in New Issue
Block a user