import { schema } from 'nexus' import StripeUtil from '../../utils/stripe' import * as Auth from '../../utils/auth' import { logger } from '../../utils/logger' import { Stripe } from 'stripe' export const PaymentMethod = schema.objectType({ name: 'PaymentMethod', definition(t) { t.model.id() t.model.type() t.model.createdAt() t.model.updatedAt() t.model.isSelected() t.model.uniqueToken() t.model.stripeCardId() // TODO: Unsure t.model.ownerId() t.model.owner() t.model.payments() t.model.creditCard() }, }) export const PaymentMethodQueries = schema.extendType({ type: 'Query', definition(t) { t.crud.paymentMethod() t.crud.paymentMethods({ filtering: true, ordering: true }) }, }) export const PaymentMethodMutation = schema.extendType({ type: 'Mutation', definition: (t) => { t.crud.deleteOnePaymentMethod({ alias: 'deletePaymentMethod' }) t.crud.updateOnePaymentMethod({ alias: 'updatePaymentMethod' }) t.crud.createOnePaymentMethod({ alias: 'createPaymentMethod' }) t.field('createPaymentMethod', { type: 'PaymentMethod', args: { data: schema.arg({ type: 'PaymentMethodCreateInput' }), }, resolve: async (parent, { data }, ctx: NexusContext) => { if (!data.uniqueToken) { throw new Error('Token is needed') } const id = Auth.getUserId(ctx) const currentUser = await ctx.prisma.user.findOne({ where: { id: id } }) let stripeCardId const createStripeCustomerHelper = async () => { // Put stripeCustomerId to null because we want a new stripe user const customer: Stripe.Customer = ( await StripeUtil.createStripeCustomer( { ...currentUser, stripeCustomerId: null }, data.uniqueToken ) ) stripeCardId = customer.sources.data[0].id return ctx.prisma.user.update({ where: { id }, data: { stripeCustomerId: customer.id, }, }) } if (!currentUser.stripeCustomerId) { await createStripeCustomerHelper() } else { try { const source = await StripeUtil.createSource( currentUser.stripeCustomerId, data.uniqueToken ) stripeCardId = source.id } catch (e) { console.log('ERROR in createSource in createPaymentMethod', e) // Maybe the stripeCustomerId isn't good so create a new one await createStripeCustomerHelper() } } // WFTF ? return ctx.prisma.paymentMethod.create({ data: { ...data, stripeCardId, }, }) }, }) t.field('updatePaymentMethod', { type: 'PaymentMethod', args: { data: schema.arg({ type: 'PaymentMethodUpdateInput' }), where: schema.arg({ type: 'PaymentMethodWhereUniqueInput' }), }, resolve: async (parent, { where, data }, ctx: NexusContext) => { const id = Auth.getUserId(ctx) const currentUser = await ctx.prisma.user.findOne({ where: { id } }) const previousPaymentMethod = await ctx.prisma.paymentMethod.findOne({ where }) if (previousPaymentMethod.isSelected !== data.isSelected) { try { await StripeUtil.updateDefaultSourceOfCustomer( currentUser.stripeCustomerId, previousPaymentMethod.stripeCardId ) } catch (e) { // Delete payment method since we can't update it because of an error await ctx.prisma.paymentMethod.delete({ where: { id: previousPaymentMethod.id } }) throw new Error("Can't update card in Stripe") } } return ctx.prisma.paymentMethod.update({ data, where }) }, }) t.field('deletePaymentMethod', { type: 'PaymentMethod', args: { where: schema.arg({ type: 'PaymentMethodWhereUniqueInput' }), }, resolve: async (parent, { where }, ctx: NexusContext) => { const paymentMethodToDelete = await ctx.prisma.paymentMethod.findOne({ where, select: { stripeCardId: true, owner: { select: { stripeCustomerId: true, }, }, }, }) try { await StripeUtil.deleteStripeSource( paymentMethodToDelete.owner.stripeCustomerId, paymentMethodToDelete.stripeCardId ) } catch (error) { logger.error(error) } return ctx.prisma.paymentMethod.delete({ where }) }, }) }, })