Skip to content

Commit

Permalink
FIX: One-time purchase pending invoice item (#210)
Browse files Browse the repository at this point in the history
This change ensures we attach the invoice item to the invoice to avoid
any occurrences of an empty invoice being paid with pending invoice
items.
  • Loading branch information
oblakeerickson committed May 7, 2024
1 parent e132913 commit d63c84e
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,16 +100,22 @@ def create
else
coupon_id = promo_code[:coupon][:id] if promo_code && promo_code[:coupon] &&
promo_code[:coupon][:id]
invoice = ::Stripe::Invoice.create(customer: customer[:id])
invoice_item =
::Stripe::InvoiceItem.create(
customer: customer[:id],
price: params[:plan],
discounts: [{ coupon: coupon_id }],
invoice: invoice[:id],
)
invoice = ::Stripe::Invoice.create(customer: customer[:id])
transaction = ::Stripe::Invoice.finalize_invoice(invoice[:id])
payment_intent = retrieve_payment_intent(transaction[:id]) if transaction[:status] ==
"open"
if payment_intent.nil?
return(
render_json_error I18n.t("js.discourse_subscriptions.subscribe.transaction_error")
)
end
transaction = ::Stripe::Invoice.pay(invoice[:id]) if payment_intent[:status] ==
"successful"
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ def parse_invoices(all_invoices, product_ids)
invoices_with_products =
all_invoices[:data].select do |invoice|
invoice_lines = invoice[:lines][:data][0] if invoice[:lines] && invoice[:lines][:data]
invoice_product_id = parse_invoice_lines(invoice_lines)
product_ids.include?(invoice_product_id)
if invoice_lines
invoice_product_id = parse_invoice_lines(invoice_lines)
product_ids.include?(invoice_product_id)
end
end
end

Expand Down
34 changes: 32 additions & 2 deletions spec/requests/subscribe_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,35 @@
}.to change { DiscourseSubscriptions::Customer.count }
end

it "returns 422 on a one time payment subscription error" do
# It's possible that the invoice item doesn't get attached
# to the invoice. This means the invoice is paid, but for $0.00 with
# a pending invoice item.
::Stripe::Price.expects(:retrieve).returns(
type: "one_time",
product: "product_12345",
metadata: {
group_name: "awesome",
},
)

::Stripe::InvoiceItem.expects(:create)

::Stripe::Invoice.expects(:create).returns(status: "open", id: "in_123")

::Stripe::Invoice.expects(:finalize_invoice).returns(
id: "in_123",
status: "paid",
payment_intent: "pi_123",
)

expect {
post "/s/create.json", params: { plan: "plan_1234", source: "tok_1234" }
}.not_to change { DiscourseSubscriptions::Customer.count }

expect(response.status).to eq 422
end

it "creates a one time payment subscription" do
::Stripe::Price.expects(:retrieve).returns(
type: "one_time",
Expand Down Expand Up @@ -414,14 +443,15 @@
},
)

::Stripe::Invoice.expects(:create).returns(status: "open", id: "in_123")

::Stripe::InvoiceItem.expects(:create).with(
customer: "cus_1234",
price: "plan_1234",
discounts: [{ coupon: "c123" }],
invoice: "in_123",
)

::Stripe::Invoice.expects(:create).returns(status: "open", id: "in_123")

::Stripe::Invoice.expects(:finalize_invoice).returns(
id: "in_123",
status: "open",
Expand Down

0 comments on commit d63c84e

Please sign in to comment.