@@ -30,6 +30,26 @@ import { quickValidateEmail } from '@/lib/messaging/email/validation'
3030
3131const logger = createLogger ( 'StripeInvoiceWebhooks' )
3232
33+ function getSubscriptionLinePeriod (
34+ invoice : Stripe . Invoice ,
35+ stripeSubscriptionId : string
36+ ) : { periodStart : Date ; periodEnd : Date } | null {
37+ const subscriptionLine = invoice . lines ?. data ?. find (
38+ ( line ) =>
39+ line . parent ?. type === 'subscription_item_details' &&
40+ line . parent . subscription_item_details ?. subscription === stripeSubscriptionId
41+ )
42+
43+ if ( ! subscriptionLine ?. period ?. start || ! subscriptionLine . period . end ) {
44+ return null
45+ }
46+
47+ return {
48+ periodStart : new Date ( subscriptionLine . period . start * 1000 ) ,
49+ periodEnd : new Date ( subscriptionLine . period . end * 1000 ) ,
50+ }
51+ }
52+
3353const METADATA_SUBSCRIPTION_INVOICE_TYPES = new Set < string > ( [
3454 'overage_billing' ,
3555 'overage_threshold_billing' ,
@@ -781,7 +801,16 @@ export async function handleInvoicePaymentSucceeded(event: Stripe.Event) {
781801 }
782802
783803 if ( wasBlocked && ! isProrationInvoice ) {
784- await resetUsageForSubscription ( { plan : sub . plan , referenceId : sub . referenceId } )
804+ const invoicePeriod = getSubscriptionLinePeriod (
805+ invoice ,
806+ resolvedInvoice . stripeSubscriptionId
807+ )
808+ await resetUsageForSubscription ( {
809+ plan : sub . plan ,
810+ referenceId : sub . referenceId ,
811+ periodStart : invoicePeriod ?. periodStart ?? null ,
812+ periodEnd : invoicePeriod ?. periodEnd ?? null ,
813+ } )
785814 }
786815 }
787816 )
@@ -922,8 +951,22 @@ export async function handleInvoiceFinalized(event: Stripe.Event) {
922951 if ( records . length === 0 ) return
923952 const sub = records [ 0 ]
924953
954+ const invoicePeriod = getSubscriptionLinePeriod ( invoice , stripeSubscriptionId )
955+ if ( ! invoicePeriod ) {
956+ logger . error ( 'Missing subscription line period on subscription cycle invoice' , {
957+ invoiceId : invoice . id ,
958+ stripeSubscriptionId,
959+ } )
960+ return
961+ }
962+
925963 if ( isEnterprise ( sub . plan ) ) {
926- await resetUsageForSubscription ( { plan : sub . plan , referenceId : sub . referenceId } )
964+ await resetUsageForSubscription ( {
965+ plan : sub . plan ,
966+ referenceId : sub . referenceId ,
967+ periodStart : invoicePeriod . periodStart ,
968+ periodEnd : invoicePeriod . periodEnd ,
969+ } )
927970 return
928971 }
929972
@@ -932,16 +975,13 @@ export async function handleInvoiceFinalized(event: Stripe.Event) {
932975 event . id ,
933976 async ( ) => {
934977 const stripe = requireStripeClient ( )
935- const periodStart = invoice . lines ?. data ?. [ 0 ] ?. period ?. start || invoice . period_start || null
936- const periodEnd =
937- invoice . lines ?. data ?. [ 0 ] ?. period ?. end ||
938- invoice . period_end ||
939- Math . floor ( Date . now ( ) / 1000 )
978+ const periodStart = Math . floor ( invoicePeriod . periodStart . getTime ( ) / 1000 )
979+ const periodEnd = Math . floor ( invoicePeriod . periodEnd . getTime ( ) / 1000 )
940980 const billingPeriod = new Date ( periodEnd * 1000 ) . toISOString ( ) . slice ( 0 , 7 )
941981
942982 const totalOverage = await calculateSubscriptionOverage ( {
943983 ...sub ,
944- periodStart : periodStart ? new Date ( periodStart * 1000 ) : sub . periodStart ,
984+ periodStart : new Date ( periodStart * 1000 ) ,
945985 periodEnd : new Date ( periodEnd * 1000 ) ,
946986 } )
947987
@@ -1134,8 +1174,8 @@ export async function handleInvoiceFinalized(event: Stripe.Event) {
11341174 await resetUsageForSubscription ( {
11351175 plan : sub . plan ,
11361176 referenceId : sub . referenceId ,
1137- periodStart : periodStart ? new Date ( periodStart * 1000 ) : sub . periodStart ,
1138- periodEnd : new Date ( periodEnd * 1000 ) ,
1177+ periodStart : invoicePeriod . periodStart ,
1178+ periodEnd : invoicePeriod . periodEnd ,
11391179 } )
11401180
11411181 return { totalOverage, creditsApplied, amountToBillStripe }
0 commit comments