Skip to content

Commit

Permalink
server/checkout: fix support for fully discounted custom pricing
Browse files Browse the repository at this point in the history
  • Loading branch information
frankie567 committed Jan 13, 2025
1 parent 575c6eb commit e7f7d02
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 19 deletions.
52 changes: 33 additions & 19 deletions server/polar/checkout/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -909,26 +909,10 @@ async def handle_stripe_success(
stripe_price_id = product_price.stripe_price_id
# For pay-what-you-want prices, we need to generate a dedicated price in Stripe
if isinstance(product_price, ProductPriceCustom):
assert checkout.amount is not None
assert checkout.currency is not None
assert checkout.product.stripe_product_id is not None
price_params: stripe_lib.Price.CreateParams = {
"unit_amount": checkout.amount,
"currency": checkout.currency,
"metadata": {
"product_price_id": str(checkout.product_price_id),
},
}
if product_price.is_recurring:
price_params["recurring"] = {
"interval": product_price.recurring_interval.as_literal(),
}
stripe_custom_price = await stripe_service.create_price_for_product(
checkout.product.stripe_product_id,
price_params,
idempotency_key=f"{idempotency_key}_price",
ad_hoc_price = await self._create_ad_hoc_custom_price(
checkout, idempotency_key=f"{idempotency_key}_price"
)
stripe_price_id = stripe_custom_price.id
stripe_price_id = ad_hoc_price.id

if product_price.is_recurring:
subscription = checkout.subscription
Expand Down Expand Up @@ -1068,6 +1052,13 @@ async def handle_free_success(
}
idempotency_key = f"checkout_{checkout.id}"

# For pay-what-you-want prices, we need to generate a dedicated price in Stripe
if isinstance(product_price, ProductPriceCustom):
ad_hoc_price = await self._create_ad_hoc_custom_price(
checkout, idempotency_key=f"{idempotency_key}_price"
)
stripe_price_id = ad_hoc_price.id

if product_price.is_recurring:
(
stripe_subscription,
Expand Down Expand Up @@ -1676,6 +1667,29 @@ async def _create_or_update_customer(

return customer

async def _create_ad_hoc_custom_price(
self, checkout: Checkout, *, idempotency_key: str
) -> stripe_lib.Price:
assert checkout.amount is not None
assert checkout.currency is not None
assert checkout.product.stripe_product_id is not None
price_params: stripe_lib.Price.CreateParams = {
"unit_amount": checkout.amount,
"currency": checkout.currency,
"metadata": {
"product_price_id": str(checkout.product_price_id),
},
}
if checkout.product_price.is_recurring:
price_params["recurring"] = {
"interval": checkout.product_price.recurring_interval.as_literal(),
}
return await stripe_service.create_price_for_product(
checkout.product.stripe_product_id,
price_params,
idempotency_key=idempotency_key,
)

async def _get_eager_loaded_checkout(
self, session: AsyncSession, checkout_id: uuid.UUID
) -> Checkout | None:
Expand Down
28 changes: 28 additions & 0 deletions server/tests/checkout/test_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -2678,6 +2678,34 @@ async def test_valid_discount_percentage_100(
stripe_service_mock.set_automatically_charged_subscription.assert_called_once()
stripe_service_mock.create_out_of_band_invoice.assert_not_called()

async def test_valid_custom_pricing_discount_percentage_100(
self,
save_fixture: SaveFixture,
stripe_service_mock: MagicMock,
session: AsyncSession,
product_one_time_custom_price: Product,
discount_percentage_100: Discount,
) -> None:
checkout = await create_checkout(
save_fixture,
price=product_one_time_custom_price.prices[0],
amount=1000,
status=CheckoutStatus.confirmed,
discount=discount_percentage_100,
payment_processor_metadata={"customer_id": "STRIPE_CUSTOMER_ID"},
)

stripe_service_mock.create_out_of_band_invoice.return_value = SimpleNamespace(
id="STRIPE_INVOICE_ID"
)

checkout = await checkout_service.handle_free_success(session, checkout.id)

assert checkout.status == CheckoutStatus.succeeded
stripe_service_mock.create_price_for_product.assert_called_once()
stripe_service_mock.create_out_of_band_invoice.assert_called_once()
stripe_service_mock.create_out_of_band_subscription.assert_not_called()


@pytest.mark.asyncio
class TestExpireOpenCheckouts:
Expand Down

0 comments on commit e7f7d02

Please sign in to comment.