-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support for subscription renewals
- Loading branch information
Showing
13 changed files
with
250 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
api/src/subscriptions/stripeEventHandlers/invoiceCreated.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// @ts-check | ||
const functions = require('firebase-functions'); | ||
const stripe = require('../stripe'); | ||
const getFirebaseUserId = require('../getFirebaseUserId'); | ||
const { stripeSubscriptionKeys } = require('../constants'); | ||
const removeUndefined = require('../../util/removeUndefined'); | ||
const { db } = require('../../firebase'); | ||
const { sendSubscriptionRenewalEmail } = require('../../mail'); | ||
|
||
/** | ||
* Handles the `invoice.created` event from Stripe | ||
* @param {any} event | ||
* @param {import('firebase-functions/v1').Response} res | ||
* | ||
*/ | ||
module.exports = async (event, res) => { | ||
console.log('Handling invoice.created'); | ||
/** @type {import('stripe').Stripe.Invoice} */ | ||
const invoice = event.data.object; | ||
|
||
const priceIdsObj = functions.config().stripe.price_ids; | ||
const wtmgPriceIds = Object.values(priceIdsObj); | ||
|
||
const price = invoice.lines.data[0]?.price; | ||
const isWtmgSubscriptionInvoice = wtmgPriceIds.includes(price?.id || ''); | ||
if (invoice.billing_reason !== 'subscription_cycle' || !isWtmgSubscriptionInvoice) { | ||
// Ignore invoices that were created for events not related | ||
// to WTMG subscription renewals | ||
return res.sendStatus(200); | ||
} | ||
|
||
const uid = await getFirebaseUserId(invoice.customer); | ||
|
||
// Finalize the invoice | ||
const finalizedInvoice = await stripe.invoices.finalizeInvoice(invoice.id); | ||
|
||
const { renewalInvoiceLinkKey, latestInvoiceStatusKey } = stripeSubscriptionKeys; | ||
|
||
if (!finalizedInvoice.hosted_invoice_url) { | ||
const errorMsg = 'Could not correctly finalize the renewal invoice'; | ||
console.error(errorMsg); | ||
res.status(500); | ||
return res.send(errorMsg); | ||
} | ||
|
||
// | ||
// Save the renewal invoice URL in Firebase | ||
const privateUserProfileDocRef = db.doc(`users-private/${uid}`); | ||
await privateUserProfileDocRef.update( | ||
removeUndefined({ | ||
[renewalInvoiceLinkKey]: finalizedInvoice.hosted_invoice_url, | ||
[latestInvoiceStatusKey]: finalizedInvoice.status | ||
// startDate should not have changed | ||
}) | ||
); | ||
|
||
// Set the user's latest invoice state | ||
// Get public & private data | ||
const publicUserProfileDocRef = db.doc(`users/${uid}`); | ||
const [publicUserProfileData, privateUserProfileData] = ( | ||
await Promise.all([publicUserProfileDocRef.get(), privateUserProfileDocRef.get()]) | ||
).map((s) => s.data()); | ||
|
||
if ( | ||
!( | ||
publicUserProfileData && | ||
privateUserProfileData && | ||
finalizedInvoice.customer_email && | ||
finalizedInvoice.hosted_invoice_url && | ||
typeof price?.unit_amount === 'number' | ||
) | ||
) { | ||
const errorMsg = 'Missing parameters to send a subscription renewal email'; | ||
res.status(500); | ||
return res.send(errorMsg); | ||
} | ||
|
||
// Send renewal invoice email | ||
await sendSubscriptionRenewalEmail({ | ||
email: finalizedInvoice.customer_email, | ||
firstName: publicUserProfileData.firstName, | ||
renewalLink: finalizedInvoice.hosted_invoice_url, | ||
price: price.unit_amount / 100, | ||
language: privateUserProfileData.communicationLanguage | ||
}); | ||
|
||
return res.sendStatus(200); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters