@@ -9,6 +9,7 @@ import ProcessedStripeEventRepository from '../repositories/billing.processedStr
99import OrganizationRepository from '../../organizations/repositories/organizations.repository.js' ;
1010import BillingExtraBalanceRepository from '../repositories/billing.extraBalance.repository.js' ;
1111import BillingWebhookService from './billing.webhook.service.js' ;
12+ import { getDollarsToUnitRatio } from '../lib/billing.constants.js' ;
1213
1314/**
1415 * Valid plan names from config (immutable set for O(1) lookups).
@@ -296,13 +297,12 @@ const cancelSubscription = async (orgId) => {
296297 * Idempotent: `refundRequestId` is used as the idempotency key so double-clicking
297298 * the admin UI never produces a double credit.
298299 *
299- * Audit trail: logs adminUserId + chargeId + amountCents on every call.
300+ * Audit trail: logs adminUserId + chargeId + amountCents + creditUnits on every call.
300301 *
301302 * @param {string } chargeId - Stripe charge ID (ch_xxx) to correlate with the dispute.
302- * @param {number } amountCents - Amount to credit in cents (positive integer). Converted to
303- * meter units by a 1:1 mapping — callers should pass the
304- * dispute amount or a proportion; the exact unit conversion
305- * is owned by ops (they know the pack price per unit).
303+ * @param {number } amountCents - Dispute amount in cents (positive integer). Internally converted
304+ * to meter units via `config.billing.meter.dollarsToUnitRatio`
305+ * (default 1000 → $1 = 1000 units, so 5000 cents = 50,000 units).
306306 * @param {string } reason - Ops note for audit trail (stored in ledger entry refId context).
307307 * @param {string } refundRequestId - UUID per click (idempotency key).
308308 * @param {string } orgId - Organization ObjectId (string) — whose extras balance to credit.
@@ -338,14 +338,15 @@ const creditDisputeReinstated = async (chargeId, amountCents, reason, refundRequ
338338 // Idempotency key includes the refundRequestId to prevent double-click double-credit.
339339 const refId = `dispute-credit-${ refundRequestId } ` ;
340340
341- // Credit the extras balance using the compensation path .
342- // amountCents is used directly as the credit unit — ops chooses the proportional amount.
343- const result = await BillingExtraBalanceRepository . creditCompensation ( orgId , amountCents , refId , reason ) ;
341+ // Convert cents to meter units using the configured dollarsToUnitRatio .
342+ const creditUnits = Math . round ( ( amountCents / 100 ) * getDollarsToUnitRatio ( ) ) ;
343+ const result = await BillingExtraBalanceRepository . creditCompensation ( orgId , creditUnits , refId , reason ) ;
344344
345345 logger . info ( '[billing.admin] creditDisputeReinstated — applied' , {
346346 orgId,
347347 chargeId,
348348 amountCents,
349+ creditUnits,
349350 reason,
350351 refundRequestId,
351352 adminUserId,
0 commit comments