File size: 1,943 Bytes
0fd3320 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | import { WalletTransactionType } from '@repo/database';
import { prisma } from './prisma';
import { redis } from '../lib/redis';
import { logger } from '../logger';
const CACHE_KEY = (orgId: string) => `wallet:ok:${orgId}`;
export interface CreditWalletParams {
organizationId: string;
amount: number;
type: 'TOP_UP_MANUAL' | 'TOP_UP_PAYMENT' | 'ADJUSTMENT';
actorId?: string;
description?: string;
}
export async function creditWallet(params: CreditWalletParams): Promise<{ newBalance: number }> {
const { organizationId, amount, type, actorId, description } = params;
const updatedOrg = await prisma.$transaction(async tx => {
const org = await tx.organization.update({
where: { id: organizationId },
data: {
walletBalance: { increment: amount },
isHardStopped: false,
},
select: { walletBalance: true, name: true },
});
await tx.walletTransaction.create({
data: {
organizationId,
amount,
balanceAfter: org.walletBalance,
type: type as WalletTransactionType,
description,
actorId,
byok: false,
metadata: {},
},
});
await tx.auditLog.create({
data: {
action: 'WALLET_CREDIT',
actorId,
resourceId: organizationId,
details: { amount, type, description, newBalance: org.walletBalance },
},
});
return org;
});
// Invalidate cache so requireCredits picks up the new balance immediately
redis.del(CACHE_KEY(organizationId)).catch(() => {});
logger.info({ organizationId, amount, type, newBalance: updatedOrg.walletBalance }, '[WALLET-API] creditWallet success');
return { newBalance: updatedOrg.walletBalance };
}
|