From eca29fc808170e3fbe6029b90d50bfc976712bee Mon Sep 17 00:00:00 2001 From: Nada Ismail <112021025+nadaismail-stripe@users.noreply.github.com> Date: Thu, 23 Feb 2023 15:43:48 -0800 Subject: [PATCH] Automatic invoice advancement for proration (#1007) --- lib/stripe-force/constants.rb | 1 + lib/stripe-force/proration_auto_bill.rb | 2 ++ sorbet/custom/stripe.rbi | 3 +++ test/integration/test_proration_auto_bill.rb | 15 +++++++++++++++ test/support/stripe_factory.rb | 8 +++++++- 5 files changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/stripe-force/constants.rb b/lib/stripe-force/constants.rb index 793641e923..d8efd3fbc9 100644 --- a/lib/stripe-force/constants.rb +++ b/lib/stripe-force/constants.rb @@ -192,6 +192,7 @@ class FeatureFlags < T::Enum ACCOUNT_POLLING = new('account_polling') COUPONS = new('coupons') TERMINATED_ORDER_ITEM_CREDIT = new('terminated_order_item_credit') + AUTO_ADVANCE_PRORATION_INVOICE = new('auto_advance_proration_invoices') end end diff --git a/lib/stripe-force/proration_auto_bill.rb b/lib/stripe-force/proration_auto_bill.rb index 1f909cb49c..61072c850d 100644 --- a/lib/stripe-force/proration_auto_bill.rb +++ b/lib/stripe-force/proration_auto_bill.rb @@ -42,6 +42,7 @@ def self.create_invoice_from_invoice_item_event(user, invoice_item_event) # TODO we need billing to offer the ability to pass in a list of invoice items, # this logic could "scoop up" invoice items which the user does NOT intend to bill + auto_advance = user.feature_enabled? FeatureFlags::AUTO_ADVANCE_PRORATION_INVOICE invoice = Stripe::Invoice.create({ customer: customer_id, subscription: subscription_id, @@ -49,6 +50,7 @@ def self.create_invoice_from_invoice_item_event(user, invoice_item_event) # TODO should we link to the originating order? Can we extract that from the line item metadata when we have it? Translate::Metadata.metadata_key(user, MetadataKeys::PRORATION_INVOICE) => "true", }, + auto_advance: auto_advance, }, user.stripe_credentials) log.info 'invoice created for proration', invoice_id: invoice.id diff --git a/sorbet/custom/stripe.rbi b/sorbet/custom/stripe.rbi index 8da9be9dc5..fd0eb4946a 100644 --- a/sorbet/custom/stripe.rbi +++ b/sorbet/custom/stripe.rbi @@ -268,6 +268,9 @@ class Stripe::SubscriptionItem < Stripe::APIResource end class Stripe::Invoice + sig { returns(T::Boolean)} + def auto_advance; end + sig { returns(Integer)} def period_end; end diff --git a/test/integration/test_proration_auto_bill.rb b/test/integration/test_proration_auto_bill.rb index 2becb25758..ddd2e6eb82 100644 --- a/test/integration/test_proration_auto_bill.rb +++ b/test/integration/test_proration_auto_bill.rb @@ -9,10 +9,14 @@ class Critic::ProrationAutoBillTranslation < Critic::FunctionalTest end it 'creates an invoice automatically for a invoice item' do + @user.enable_feature FeatureFlags::AUTO_ADVANCE_PRORATION_INVOICE, update: true + @user.enable_feature FeatureFlags::TEST_CLOCKS, update: true + subscription = create_customer_with_subscription _, ad_hoc_price = create_price(additional_price_fields: { recurring: {}, }) + # create an invoice item that looks similar to what we'll get from add_invoice_items invoice_item = Stripe::InvoiceItem.create({ customer: subscription.customer, @@ -39,6 +43,17 @@ class Critic::ProrationAutoBillTranslation < Critic::FunctionalTest invoice = T.must(invoice) assert_equal(1, invoice.lines.count) assert_equal("true", invoice.metadata[StripeForce::Translate::Metadata.metadata_key(@user, MetadataKeys::PRORATION_INVOICE)]) + + assert(invoice.auto_advance) + assert_equal('draft', invoice.status) + + # let's advance the clock by an hour and test the invoice finalizes + stripe_customer = stripe_get(subscription.customer) + refute_nil(stripe_customer.test_clock) + advance_test_clock(stripe_customer, (Time.now + 2.hour).to_i) + + invoice = Stripe::Invoice.retrieve(invoice.id, @user.stripe_credentials) + assert_not_equal('draft', invoice.status) end describe 'skip conditions' do diff --git a/test/support/stripe_factory.rb b/test/support/stripe_factory.rb index 5a5df43fc7..e5bb8d1768 100644 --- a/test/support/stripe_factory.rb +++ b/test/support/stripe_factory.rb @@ -66,7 +66,13 @@ def create_customer_with_subscription end def create_customer_with_card - customer = create_customer + if @user.feature_enabled?(FeatureFlags::TEST_CLOCKS) && !@user.livemode + test_clock = Stripe::TestHelpers::TestClock.create({ + frozen_time: Time.now.to_i, + }, @user.stripe_credentials) + end + customer = create_customer(additional_fields: {test_clock: test_clock}) + payment_method = Stripe::PaymentMethod.attach( 'pm_card_visa', {customer: customer.id},