This commit is contained in:
Artur
2025-04-02 18:01:00 -03:00
parent 4549b73b73
commit e7f4be25c8
7 changed files with 39 additions and 21 deletions

View File

@@ -176,8 +176,11 @@ async function handleDonationOrMembership(body: WebhookBody) {
try { try {
await givePointsToUser({ pointsToGive, donation }) await givePointsToUser({ pointsToGive, donation })
} catch (error) { } catch (error) {
log('error', `[Stripe webhook] Failed to give points. Rolling back.`) log(
prisma.donation.delete({ where: { id: donation.id } }) 'error',
`[Stripe webhook] Failed to give points for invoice ${body.invoiceId}. Rolling back.`
)
await prisma.donation.delete({ where: { id: donation.id } })
throw error throw error
} }
} }
@@ -193,8 +196,9 @@ async function handleDonationOrMembership(body: WebhookBody) {
} catch (error) { } catch (error) {
log( log(
'warn', 'warn',
`[BTCPay webhook] Could not add user ${body.metadata.userId} to PG forum members group. Invoice: ${body.invoiceId}. NOT rolling back. Continuing... Cause: ${error}` `[BTCPay webhook] Could not add user ${body.metadata.userId} to PG forum members group. Invoice: ${body.invoiceId}. NOT rolling back. Continuing... Cause:`
) )
console.error(error)
} }
} }
@@ -226,7 +230,7 @@ async function handleDonationOrMembership(body: WebhookBody) {
} }
try { try {
sendDonationConfirmationEmail({ await sendDonationConfirmationEmail({
to: body.metadata.donorEmail, to: body.metadata.donorEmail,
donorName: body.metadata.donorName, donorName: body.metadata.donorName,
donation, donation,
@@ -236,8 +240,9 @@ async function handleDonationOrMembership(body: WebhookBody) {
} catch (error) { } catch (error) {
log( log(
'warn', 'warn',
`[BTCPay webhook] Failed to send donation confirmation email for invoice ${body.invoiceId}. NOT rolling back. Cause: ${error}` `[BTCPay webhook] Failed to send donation confirmation email for invoice ${body.invoiceId}. NOT rolling back. Cause:`
) )
console.error(error)
} }
} }

View File

@@ -2,6 +2,7 @@
Warnings: Warnings:
- A unique constraint covering the columns `[btcPayInvoiceId]` on the table `Donation` will be added. If there are existing duplicate values, this will fail. - A unique constraint covering the columns `[btcPayInvoiceId]` on the table `Donation` will be added. If there are existing duplicate values, this will fail.
- A unique constraint covering the columns `[stripePaymentIntentId]` on the table `Donation` will be added. If there are existing duplicate values, this will fail.
*/ */
-- AlterTable -- AlterTable
@@ -11,3 +12,6 @@ ALTER COLUMN "netCryptoAmount" SET DATA TYPE TEXT;
-- CreateIndex -- CreateIndex
CREATE UNIQUE INDEX "Donation_btcPayInvoiceId_key" ON "Donation"("btcPayInvoiceId"); CREATE UNIQUE INDEX "Donation_btcPayInvoiceId_key" ON "Donation"("btcPayInvoiceId");
-- CreateIndex
CREATE UNIQUE INDEX "Donation_stripePaymentIntentId_key" ON "Donation"("stripePaymentIntentId");

View File

@@ -38,7 +38,7 @@ model Donation {
userId String? userId String?
donorName String? donorName String?
btcPayInvoiceId String? @unique btcPayInvoiceId String? @unique
stripePaymentIntentId String? // For donations and non-recurring memberships stripePaymentIntentId String? @unique // For donations and non-recurring memberships
stripeInvoiceId String? @unique // For recurring memberships stripeInvoiceId String? @unique // For recurring memberships
stripeSubscriptionId String? // For recurring memberships stripeSubscriptionId String? // For recurring memberships
projectSlug String projectSlug String

View File

@@ -32,9 +32,9 @@ export async function sendDonationConfirmationEmail({
const fundName = funds[donation.fundSlug].title const fundName = funds[donation.fundSlug].title
const isMembership = !donation.membershipExpiresAt const isMembership = !donation.membershipExpiresAt
const isSubscription = donation.stripeSubscriptionId const isSubscription = donation.stripeSubscriptionId
const isPaidWithCrypto = (donation.cryptoPayments as DonationCryptoPayments).length const isPaidWithCrypto = (donation.cryptoPayments as DonationCryptoPayments | null)?.length
const cryptoDonationDescription = (donation.cryptoPayments as DonationCryptoPayments) const cryptoDonationDescription = (donation.cryptoPayments as DonationCryptoPayments | null)
.map((payment) => `${payment.grossAmount} ${payment.cryptoCode}`) ?.map((payment) => `${payment.grossAmount} ${payment.cryptoCode}`)
.join(', ') .join(', ')
const markdown = `# Donation receipt const markdown = `# Donation receipt

View File

@@ -76,11 +76,12 @@ export async function deductPointsFromUser({
orderId, orderId,
}: DeductPointsFromUserParams) { }: DeductPointsFromUserParams) {
const pointsBalance = await getPointsBalance(userId) const pointsBalance = await getPointsBalance(userId)
const newPointsBalance = pointsBalance - deductionAmount
await strapiApi.post<any, any, StrapiCreatePointBody>('/points', { await strapiApi.post<any, any, StrapiCreatePointBody>('/points', {
data: { data: {
balanceChange: (-deductionAmount).toString(), balanceChange: (-deductionAmount).toString(),
balance: pointsBalance.toString(), balance: newPointsBalance.toString(),
userId: userId, userId: userId,
perk: perkId, perk: perkId,
order: orderId, order: orderId,

View File

@@ -73,8 +73,11 @@ async function handleDonationOrNonRecurringMembership(paymentIntent: Stripe.Paym
try { try {
await givePointsToUser({ pointsToGive, donation }) await givePointsToUser({ pointsToGive, donation })
} catch (error) { } catch (error) {
log('error', `[Stripe webhook] Failed to give points. Rolling back.`) log(
prisma.donation.delete({ where: { id: donation.id } }) 'error',
`[Stripe webhook] Failed to give points for payment intent ${paymentIntent.id}. Rolling back.`
)
await prisma.donation.delete({ where: { id: donation.id } })
throw error throw error
} }
} }
@@ -108,7 +111,7 @@ async function handleDonationOrNonRecurringMembership(paymentIntent: Stripe.Paym
} }
try { try {
sendDonationConfirmationEmail({ await sendDonationConfirmationEmail({
to: metadata.donorEmail, to: metadata.donorEmail,
donorName: metadata.donorName, donorName: metadata.donorName,
donation, donation,
@@ -118,8 +121,9 @@ async function handleDonationOrNonRecurringMembership(paymentIntent: Stripe.Paym
} catch (error) { } catch (error) {
log( log(
'warn', 'warn',
`[Stripe webhook] Failed to send donation confirmation email for payment intent ${paymentIntent.id}. NOT rolling back. Cause ${error}` `[Stripe webhook] Failed to send donation confirmation email for payment intent ${paymentIntent.id}. NOT rolling back. Cause:`
) )
console.error(error)
} }
} }
@@ -179,8 +183,11 @@ async function handleRecurringMembership(invoice: Stripe.Invoice) {
try { try {
await givePointsToUser({ donation, pointsToGive }) await givePointsToUser({ donation, pointsToGive })
} catch (error) { } catch (error) {
log('error', `[BTCPay webhook] Failed to give points. Rolling back.`) log(
prisma.donation.delete({ where: { id: donation.id } }) 'error',
`[BTCPay webhook] Failed to give points for invoice ${invoice.id}. Rolling back.`
)
await prisma.donation.delete({ where: { id: donation.id } })
throw error throw error
} }
} }
@@ -210,7 +217,7 @@ async function handleRecurringMembership(invoice: Stripe.Invoice) {
}) })
try { try {
sendDonationConfirmationEmail({ await sendDonationConfirmationEmail({
to: metadata.donorEmail, to: metadata.donorEmail,
donorName: metadata.donorName, donorName: metadata.donorName,
donation, donation,
@@ -220,8 +227,9 @@ async function handleRecurringMembership(invoice: Stripe.Invoice) {
} catch (error) { } catch (error) {
log( log(
'warn', 'warn',
`[Stripe webhook] Failed to send donation confirmation email for invoice ${invoice.id}. NOT rolling back. Cause ${error}` `[Stripe webhook] Failed to send donation confirmation email for invoice ${invoice.id}. NOT rolling back. Cause:`
) )
console.error(error)
} }
} }

View File

@@ -110,7 +110,7 @@ if (!globalForWorker.hasInitializedWorkers)
}) })
} catch (error) { } catch (error) {
log('error', `[Perk purchase worker] Failed to create Strapi order. Rolling back.`) log('error', `[Perk purchase worker] Failed to create Strapi order. Rolling back.`)
cancelPrintfulOrder(printfulOrder?.externalId!) await cancelPrintfulOrder(printfulOrder?.externalId!)
throw error throw error
} }
@@ -124,8 +124,8 @@ if (!globalForWorker.hasInitializedWorkers)
}) })
} catch (error) { } catch (error) {
log('error', `[Perk purchase worker] Failed to deduct points. Rolling back.`) log('error', `[Perk purchase worker] Failed to deduct points. Rolling back.`)
if (printfulOrder) cancelPrintfulOrder(printfulOrder.externalId) if (printfulOrder) await cancelPrintfulOrder(printfulOrder.externalId)
deleteStrapiOrder(strapiOrder.documentId) await deleteStrapiOrder(strapiOrder.documentId)
throw error throw error
} }