fix(api): sync stripe customer email on change (#3243)

This commit is contained in:
Hampus authored and GitHub committed 2026-10-06 21:38:25 +02:00
1 parent 6e28092cdc
commit cc5545c333
17 files changed
+509 -125

No files matched your search

@@ -49,6 +49,7 @@ const LANE_CONFIG = {
'harvestUserData',
'batchGuildAuditLogMessageDeletes',
'reconcileUserPayments',
'syncStripeCustomerEmail',
'processAppStoreNotification',
'processGooglePlayNotification',
'refreshStorePurchase',
@@ -49,6 +49,7 @@ import syncCrosspostCopies from '@app/api/worker/tasks/SyncCrosspostCopies';
import syncCrosspostedMessage from '@app/api/worker/tasks/SyncCrosspostedMessage';
import syncDiscoveryIndex from '@app/api/worker/tasks/SyncDiscoveryIndex';
import syncFileShaBlocklists from '@app/api/worker/tasks/SyncFileShaBlocklists';
import syncStripeCustomerEmail from '@app/api/worker/tasks/SyncStripeCustomerEmail';
import syncUrlBlocklists from '@app/api/worker/tasks/SyncUrlBlocklists';
import userProcessPendingDeletion from '@app/api/worker/tasks/UserProcessPendingDeletion';
import userProcessPendingDeletions from '@app/api/worker/tasks/UserProcessPendingDeletions';
@@ -100,6 +101,7 @@ export const workerTasks: Record<WorkerTaskName, WorkerTaskHandler> = {
refreshSearchIndex,
removeChannelFollowers,
sendSystemDm,
syncStripeCustomerEmail,
syncFileShaBlocklists,
syncUrlBlocklists,
syncDiscoveryIndex,
@@ -6,6 +6,7 @@ import {mapGiftDurationMonthsToFields} from '@app/api/models/GiftCode';
import type {Payment} from '@app/api/models/Payment';
import type {User} from '@app/api/models/User';
import {getProductRegistry} from '@app/api/stripe/ProductRegistry';
import {syncStripeCustomerEmail} from '@app/api/stripe/StripeCustomer';
import {extractId} from '@app/api/stripe/StripeUtils';
import type {PaymentRepository} from '@app/api/user/repositories/PaymentRepository';
import {mapUserToPrivateResponse} from '@app/api/user/UserMappers';
@@ -332,6 +333,11 @@ const reconcileUserPayments: WorkerTaskHandler = async (payload, helpers) => {
if (!user.stripeCustomerId) {
return;
}
try {
await syncStripeCustomerEmail(stripe, user);
} catch (error) {
Logger.warn({userId: userIdStr, error}, 'Failed to sync Stripe customer email during payment reconciliation');
}
const payments = await paymentRepository.findPaymentsByUserId(userId);
let reconciledCount = 0;
for (const payment of payments) {
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {createUserID} from '@app/api/BrandedTypes';
import {isStripeResourceMissingError, syncStripeCustomerEmail} from '@app/api/stripe/StripeCustomer';
import {getWorkerDependencies} from '@app/api/worker/WorkerContext';
import type {WorkerTaskHandler} from '@pkgs/worker/src/contracts/WorkerTask';
const syncStripeCustomerEmailTask: WorkerTaskHandler = async (payload, helpers) => {
const {userRepository, stripe} = getWorkerDependencies();
if (!stripe) {
helpers.logger.debug('Stripe is disabled, skipping customer email sync');
return;
}
const userIdStr = payload.userId as string;
if (!userIdStr) {
helpers.logger.warn({payload}, 'Stripe customer email sync task missing userId');
return;
}
const user = await userRepository.findUnique(createUserID(BigInt(userIdStr)));
if (!user) {
return;
}
try {
await syncStripeCustomerEmail(stripe, user);
} catch (error) {
if (isStripeResourceMissingError(error)) {
helpers.logger.warn(
{userId: userIdStr, customerId: user.stripeCustomerId},
'Stripe customer no longer exists, skipping email sync',
);
return;
}
throw error;
}
};
export default syncStripeCustomerEmailTask;