Skip to content

Commit

Permalink
server: migrate direct subscription management to Sale, esp. in Trans…
Browse files Browse the repository at this point in the history
…action
  • Loading branch information
frankie567 committed May 16, 2024
1 parent 2ab059e commit 33a2767
Show file tree
Hide file tree
Showing 27 changed files with 680 additions and 489 deletions.
117 changes: 117 additions & 0 deletions server/migrations/versions/2024-05-16-1358_migrate_heldbalance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
"""Migrate HeldBalance
Revision ID: f850759b02d5
Revises: e553ec9cf929
Create Date: 2024-05-16 13:58:23.584174
"""

import sqlalchemy as sa
from alembic import op

# Polar Custom Imports
from polar.kit.extensions.sqlalchemy import PostgresUUID

# revision identifiers, used by Alembic.
revision = "f850759b02d5"
down_revision = "e553ec9cf929"
branch_labels: tuple[str] | None = None
depends_on: tuple[str] | None = None


def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column("held_balances", sa.Column("sale_id", sa.UUID(), nullable=True))
op.create_foreign_key(
op.f("held_balances_sale_id_fkey"),
"held_balances",
"sales",
["sale_id"],
["id"],
ondelete="set null",
)

op.execute(
"""
UPDATE held_balances
SET sale_id = sales.id
FROM sales
JOIN subscriptions ON sales.subscription_id = subscriptions.id
WHERE held_balances.subscription_id = subscriptions.id
"""
)

op.drop_index("ix_held_balances_product_price_id", table_name="held_balances")
op.drop_index("ix_held_balances_subscription_id", table_name="held_balances")
op.create_index(
op.f("ix_held_balances_sale_id"), "held_balances", ["sale_id"], unique=False
)
op.drop_constraint(
"held_balances_subscription_id_fkey", "held_balances", type_="foreignkey"
)
op.drop_constraint(
"held_balances_subscription_tier_price_id_fkey",
"held_balances",
type_="foreignkey",
)

op.drop_column("held_balances", "product_price_id")
op.drop_column("held_balances", "subscription_id")
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column(
"held_balances",
sa.Column("subscription_id", sa.UUID(), autoincrement=False, nullable=True),
)
op.add_column(
"held_balances",
sa.Column("product_price_id", sa.UUID(), autoincrement=False, nullable=True),
)
op.create_foreign_key(
"held_balances_subscription_tier_price_id_fkey",
"held_balances",
"product_prices",
["product_price_id"],
["id"],
ondelete="SET NULL",
)
op.create_foreign_key(
"held_balances_subscription_id_fkey",
"held_balances",
"subscriptions",
["subscription_id"],
["id"],
ondelete="SET NULL",
)

op.execute(
"""
UPDATE held_balances
SET subscription_id = sales.subscription_id,
product_price_id = sales.product_price_id
FROM sales
WHERE sales.id = held_balances.sale_id
"""
)

op.drop_constraint(
op.f("held_balances_sale_id_fkey"), "held_balances", type_="foreignkey"
)
op.drop_index(op.f("ix_held_balances_sale_id"), table_name="held_balances")
op.create_index(
"ix_held_balances_subscription_id",
"held_balances",
["subscription_id"],
unique=False,
)
op.create_index(
"ix_held_balances_product_price_id",
"held_balances",
["product_price_id"],
unique=False,
)
op.drop_column("held_balances", "sale_id")
# ### end Alembic commands ###
6 changes: 2 additions & 4 deletions server/polar/held_balance/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@ async def release_account(
.options(
joinedload(HeldBalance.payment_transaction),
joinedload(HeldBalance.pledge),
joinedload(HeldBalance.subscription),
joinedload(HeldBalance.product_price),
joinedload(HeldBalance.sale),
joinedload(HeldBalance.issue_reward),
joinedload(HeldBalance.donation),
)
Expand All @@ -70,8 +69,7 @@ async def release_account(
payment_transaction=held_balance.payment_transaction,
amount=held_balance.amount,
pledge=held_balance.pledge,
subscription=held_balance.subscription,
product_price=held_balance.product_price,
sale=held_balance.sale,
issue_reward=held_balance.issue_reward,
donation=held_balance.donation,
)
Expand Down
9 changes: 2 additions & 7 deletions server/polar/integrations/stripe/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
ProductType,
)
from polar.pledge.service import pledge as pledge_service
from polar.sale.service import sale as sale_service
from polar.subscription.service.subscription import SubscriptionDoesNotExist
from polar.subscription.service.subscription import subscription as subscription_service
from polar.transaction.service.balance import PaymentTransactionForChargeDoesNotExist
Expand All @@ -28,9 +29,6 @@
from polar.transaction.service.payment import (
PledgeDoesNotExist as PaymentTransactionPledgeDoesNotExist,
)
from polar.transaction.service.payment import (
SubscriptionDoesNotExist as PaymentTransactionSubscriptionDoesNotExist,
)
from polar.transaction.service.payment import (
payment_transaction as payment_transaction_service,
)
Expand Down Expand Up @@ -139,7 +137,6 @@ async def charge_succeeded(
)
except (
PaymentTransactionPledgeDoesNotExist,
PaymentTransactionSubscriptionDoesNotExist,
PaymentTransactionDonationDoesNotExist,
) as e:
# Retry because we might not have been able to handle other events
Expand Down Expand Up @@ -278,9 +275,7 @@ async def invoice_paid(
async with AsyncSessionMaker(ctx) as session:
invoice = stripe.Invoice.construct_from(event["data"]["object"], None)
try:
await subscription_service.transfer_subscription_paid_invoice(
session, invoice=invoice
)
await sale_service.create_sale_from_stripe(session, invoice=invoice)
except (
SubscriptionDoesNotExist,
PaymentTransactionForChargeDoesNotExist,
Expand Down
30 changes: 6 additions & 24 deletions server/polar/models/held_balance.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
IssueReward,
Organization,
Pledge,
ProductPrice,
Subscription,
Sale,
Transaction,
)

Expand Down Expand Up @@ -89,34 +88,17 @@ def payment_transaction(cls) -> Mapped["Transaction"]:
def pledge(cls) -> Mapped["Pledge | None"]:
return relationship("Pledge", lazy="raise")

subscription_id: Mapped[UUID | None] = mapped_column(
sale_id: Mapped[UUID | None] = mapped_column(
PostgresUUID,
ForeignKey("subscriptions.id", ondelete="set null"),
ForeignKey("sales.id", ondelete="set null"),
nullable=True,
index=True,
)
"""ID of the `Subscription` related to this balance."""
"""ID of the `Sale` related to this balance."""

@declared_attr
def subscription(cls) -> Mapped["Subscription | None"]:
return relationship("Subscription", lazy="raise")

product_price_id: Mapped[UUID | None] = mapped_column(
PostgresUUID,
ForeignKey("product_prices.id", ondelete="set null"),
nullable=True,
index=True,
)
"""
ID of the `ProductPrice` related to this balance.
Useful to keep track of the price at the time of the balance creation,
which might change if the product is updated.
"""

@declared_attr
def product_price(cls) -> Mapped["ProductPrice | None"]:
return relationship("ProductPrice", lazy="raise")
def sale(cls) -> Mapped["Sale | None"]:
return relationship("Sale", lazy="raise")

issue_reward_id: Mapped[UUID | None] = mapped_column(
PostgresUUID,
Expand Down
9 changes: 0 additions & 9 deletions server/polar/product/service/product.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from sqlalchemy.exc import InvalidRequestError
from sqlalchemy.orm import contains_eager, joinedload

from polar.account.service import account as account_service
from polar.auth.models import AuthSubject, Subject, is_organization, is_user
from polar.authz.service import AccessType, Authz
from polar.benefit.service.benefit import benefit as benefit_service
Expand All @@ -17,7 +16,6 @@
from polar.kit.pagination import PaginationParams, paginate
from polar.kit.services import ResourceService
from polar.models import (
Account,
Benefit,
Organization,
Product,
Expand Down Expand Up @@ -511,13 +509,6 @@ def _get_readable_product_statement(

return statement

async def get_managing_organization_account(
self, session: AsyncSession, product: Product
) -> Account | None:
return await account_service.get_by_organization_id(
session, product.organization_id
)

async def _disable_other_highlights(
self,
session: AsyncSession,
Expand Down
Empty file added server/polar/sale/__init__.py
Empty file.
Loading

0 comments on commit 33a2767

Please sign in to comment.