@@ -7,11 +7,15 @@ import {
77} from './parser'
88import {
99 TRANSITION_PERIOD_INCLUDED_CREDITS_POLICY ,
10+ resolveIncludedCreditsPolicy ,
1011 type IncludedCreditsPolicy ,
1112 type OrganizationIncludedCreditTier ,
1213 type PlanIdentity ,
14+ type ReportPeriod ,
1315} from './includedCreditsPolicy'
16+ import { isValidIsoDate } from './isoDate'
1417import { streamLines , type StreamProgress } from './streamer'
18+ import type { ReportFormatMetadata } from './reportAdapters'
1519
1620type IndividualPlan = 'pro-student' | 'pro-plus'
1721
@@ -87,6 +91,7 @@ export type LicenseSummary = {
8791export interface AicIncludedCreditsProgressOptions {
8892 onProgress ?: ( progress : StreamProgress ) => void
8993 includedCreditsPolicy ?: IncludedCreditsPolicy
94+ reportMetadata ?: ReportFormatMetadata
9095}
9196
9297type ReportScopeUser = {
@@ -224,6 +229,31 @@ export function getIndividualMonthlyAicIncludedCredits(
224229 return findIndividualIncludedCreditsPlan ( totalMonthlyQuota , reportPlanScope ) ?. monthlyIncludedCredits ?? 0
225230}
226231
232+ function includeDateInReportPeriod ( reportPeriod : ReportPeriod , rawDate : string ) : ReportPeriod {
233+ const date = rawDate . trim ( )
234+ if ( ! isValidIsoDate ( date ) ) return reportPeriod
235+
236+ return {
237+ startDate : ! reportPeriod . startDate || date < reportPeriod . startDate ? date : reportPeriod . startDate ,
238+ endDate : ! reportPeriod . endDate || date > reportPeriod . endDate ? date : reportPeriod . endDate ,
239+ }
240+ }
241+
242+ function resolvePolicyForContext (
243+ options : AicIncludedCreditsProgressOptions | undefined ,
244+ reportPeriod : ReportPeriod ,
245+ ) : IncludedCreditsPolicy {
246+ if ( options ?. includedCreditsPolicy ) {
247+ return options . includedCreditsPolicy
248+ }
249+
250+ if ( options ?. reportMetadata ) {
251+ return resolveIncludedCreditsPolicy ( options . reportMetadata , reportPeriod )
252+ }
253+
254+ return TRANSITION_PERIOD_INCLUDED_CREDITS_POLICY
255+ }
256+
227257export function calculateLicenseSummary (
228258 users : Array < { totalMonthlyQuota : number } & ReportScopeUser > ,
229259 policy : IncludedCreditsPolicy = TRANSITION_PERIOD_INCLUDED_CREDITS_POLICY ,
@@ -274,10 +304,10 @@ export async function calculateAicIncludedCreditsContext(
274304 overrides : AicIncludedCreditsOverrides = { } ,
275305 options ?: AicIncludedCreditsProgressOptions ,
276306) : Promise < AicIncludedCreditsContext > {
277- const includedCreditsPolicy = options ?. includedCreditsPolicy ?? TRANSITION_PERIOD_INCLUDED_CREDITS_POLICY
278307 let header : TokenUsageHeader | null = null
279- const quotasByUser = new Map < string , number > ( )
308+ const quotaCandidatesByUser = new Map < string , Set < number > > ( )
280309 let hasOrganizationContext = false
310+ let reportPeriod : ReportPeriod = { }
281311
282312 for await ( const line of streamLines ( file , options ) ) {
283313 const trimmed = line . trimEnd ( )
@@ -291,22 +321,30 @@ export async function calculateAicIncludedCreditsContext(
291321 const record = parseNormalizedTokenUsageRecord ( trimmed , header )
292322 if ( ! record ) continue
293323
324+ reportPeriod = includeDateInReportPeriod ( reportPeriod , record . date )
325+
294326 const username = record . username . trim ( )
295327 if ( ! username ) continue
296328
297329 if ( record . organization . trim ( ) || ( record . cost_center_name ?. trim ( ) ?? '' ) ) {
298330 hasOrganizationContext = true
299331 }
300332
301- const currentQuota = quotasByUser . get ( username ) ?? 0
302- quotasByUser . set ( username , selectKnownMonthlyQuota (
303- currentQuota ,
304- record . total_monthly_quota ,
305- includedCreditsPolicy ,
306- ) )
333+ const quotaCandidates = quotaCandidatesByUser . get ( username ) ?? new Set < number > ( )
334+ quotaCandidates . add ( record . total_monthly_quota )
335+ quotaCandidatesByUser . set ( username , quotaCandidates )
307336 }
308337
309- const reportPlanScope = inferReportPlanScope ( quotasByUser . size , hasOrganizationContext )
338+ const includedCreditsPolicy = resolvePolicyForContext ( options , reportPeriod )
339+ const quotasByUser = new Map < string , number > ( )
340+ quotaCandidatesByUser . forEach ( ( quotaCandidates , username ) => {
341+ quotasByUser . set ( username , Array . from ( quotaCandidates ) . reduce (
342+ ( currentQuota , candidateQuota ) => selectKnownMonthlyQuota ( currentQuota , candidateQuota , includedCreditsPolicy ) ,
343+ 0 ,
344+ ) )
345+ } )
346+
347+ const reportPlanScope = inferReportPlanScope ( quotaCandidatesByUser . size , hasOrganizationContext )
310348 if ( reportPlanScope === 'individual' ) {
311349 const quota = quotasByUser . values ( ) . next ( ) . value ?? 0
312350 return {
0 commit comments