Skip to content

Commit

Permalink
Handle Stripe Payment_intent.canceled event (#321)
Browse files Browse the repository at this point in the history
* added  @StripeWebhookHandler('payment_intent.canceled') and consolidated all handlers into a single StripePaymentService class

* added tests for stripe hooks and moved test data in separate file

Co-authored-by: quantum-grit <[email protected]>
  • Loading branch information
quantum-grit and quantum-grit authored Aug 11, 2022
1 parent 930eb47 commit f6e4f67
Show file tree
Hide file tree
Showing 11 changed files with 1,470 additions and 864 deletions.
4 changes: 3 additions & 1 deletion TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,7 @@ yarn dev
In a third shell trigger individual stripe events on demand

```shell
stripe trigger payment_intent.succeeded
stripe trigger payment_intent.succeeded --override payment_intent:metadata.campaignId=e8bf74dd-6212-4a0e-b192-56e4eb19e1f2 --override payment_intent:currency=BGN
```

Important - From the the Stripe CLI docs: Triggering some events like payment_intent.succeeded or payment_intent.canceled will also send you a payment_intent.created event for completeness.
50 changes: 29 additions & 21 deletions apps/api/src/campaign/campaign.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ export class CampaignService {
newDonationStatus: DonationStatus,
) {
const campaignId = campaign.id
Logger.debug('[Stripe webhook] Update donation from state initial to waiting', {
Logger.debug('[Stripe webhook] Update donation to status: ' + newDonationStatus, {
campaignId,
paymentIntentId: paymentData.paymentIntentId,
})
Expand All @@ -298,7 +298,7 @@ export class CampaignService {
: // Create new vault for the campaign
{ create: { campaignId, currency: campaign.currency, name: campaign.title } }

// Find donation by extPaymentIntentId an update if status allows
// Find donation by extPaymentIntentId and update if status allows

const donation = await this.prisma.donation.findUnique({
where: { extPaymentIntentId: paymentData.paymentIntentId },
Expand All @@ -307,28 +307,36 @@ export class CampaignService {

//if missing create the donation with the incoming status
if (!donation) {
Logger.error(
Logger.debug(
'No donation exists with extPaymentIntentId: ' +
paymentData.paymentIntentId +
' Creating new donation with status: ' +
newDonationStatus,
)
this.prisma.donation.create({
data: {
amount: paymentData.netAmount,
chargedAmount: paymentData.chargedAmount,
currency: campaign.currency,
targetVault: targetVaultData,
provider: PaymentProvider.stripe,
type: DonationType.donation,
status: newDonationStatus,
extCustomerId: paymentData.stripeCustomerId ?? '',
extPaymentIntentId: paymentData.paymentIntentId,
extPaymentMethodId: paymentData.paymentMethodId ?? '',
billingName: paymentData.billingName,
billingEmail: paymentData.billingEmail,
},
})

try {
await this.prisma.donation.create({
data: {
amount: paymentData.netAmount,
chargedAmount: paymentData.chargedAmount,
currency: campaign.currency,
targetVault: targetVaultData,
provider: PaymentProvider.stripe,
type: DonationType.donation,
status: newDonationStatus,
extCustomerId: paymentData.stripeCustomerId ?? '',
extPaymentIntentId: paymentData.paymentIntentId,
extPaymentMethodId: paymentData.paymentMethodId ?? '',
billingName: paymentData.billingName,
billingEmail: paymentData.billingEmail,
},
})
} catch (error) {
Logger.error(
`[Stripe webhook] Error while creating donation with paymentIntentId: ${paymentData.paymentIntentId} and status: ${newDonationStatus} . Error is: ${error}`,
)
throw new InternalServerErrorException(error)
}

return
}
Expand Down Expand Up @@ -360,7 +368,7 @@ export class CampaignService {
}
//donation exists but we need to skip because previous status is from later event than the incoming
else {
Logger.error(
Logger.warn(
`[Stripe webhook] Skipping update of donation with paymentIntentId: ${paymentData.paymentIntentId}
and status: ${newDonationStatus} because the event comes after existing donation with status: ${donation.status}`,
)
Expand All @@ -375,7 +383,7 @@ export class CampaignService {
chargedAmount: paymentData.chargedAmount,
})

this.updateDonationPayment(campaign, paymentData, DonationStatus.succeeded)
await this.updateDonationPayment(campaign, paymentData, DonationStatus.succeeded)

const vault = await this.getCampaignVault(campaign.id)
if (vault) {
Expand Down
6 changes: 2 additions & 4 deletions apps/api/src/donations/donations.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ import { VaultModule } from '../vault/vault.module'
import { VaultService } from '../vault/vault.service'
import { DonationsController } from './donations.controller'
import { DonationsService } from './donations.service'
import { PaymentCreatedService } from './events/payment-created.service'
import { PaymentSucceededService } from './events/payment-intent-succeeded.service'
import { StripePaymentService } from './events/stripe-payment.service'

@Module({
imports: [
Expand All @@ -27,8 +26,7 @@ import { PaymentSucceededService } from './events/payment-intent-succeeded.servi
controllers: [DonationsController],
providers: [
DonationsService,
PaymentCreatedService,
PaymentSucceededService,
StripePaymentService,
CampaignService,
PrismaService,
VaultService,
Expand Down
53 changes: 0 additions & 53 deletions apps/api/src/donations/events/payment-created.service.ts

This file was deleted.

44 changes: 0 additions & 44 deletions apps/api/src/donations/events/payment-intent-succeeded.service.ts

This file was deleted.

Loading

0 comments on commit f6e4f67

Please sign in to comment.