Skip to content

Commit

Permalink
server: Allow reused customer email after deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
birkjernstrom committed Jan 2, 2025
1 parent 4d24d0b commit 4c6e2b8
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 1 deletion.
2 changes: 1 addition & 1 deletion server/polar/customer/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ async def update(
async def delete(self, session: AsyncSession, customer: Customer) -> Customer:
# TODO: cancel subscriptions, revoke benefits, etc.

customer.set_deleted_at()
customer.mark_deleted()
session.add(customer)
return customer

Expand Down
8 changes: 8 additions & 0 deletions server/polar/models/customer.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,11 @@ def legacy_user_public_name(self) -> str:
if self.name:
return self.name[0]
return self.email[0]

def mark_deleted(self) -> None:
# We do soft deletes (transaction records).
# So prefix email as deleted to free up the real one for future purchases.
now = int(time.time())
email = f"deleted.{now}.{self.email}"
self.email = email
self.set_deleted_at()
55 changes: 55 additions & 0 deletions server/tests/customer/test_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
from polar.models import Customer, Organization, User, UserOrganization
from polar.postgres import AsyncSession
from tests.fixtures.auth import AuthSubjectFixture
from tests.fixtures.database import SaveFixture
from tests.fixtures.random_objects import create_customer


@pytest.fixture
Expand Down Expand Up @@ -122,3 +124,56 @@ async def test_valid(

assert customer.email == email
assert customer.name == "John"


@pytest.mark.asyncio
class TestDelete:

async def test_valid(
self,
session: AsyncSession,
save_fixture: SaveFixture,
organization: Organization,
customer: Customer,
) -> None:
customer = await create_customer(
save_fixture,
organization=organization,
email="[email protected]",
)
customer = await customer_service.delete(
session,
customer,
)
await session.flush()
assert customer.deleted_at is not None

async def test_valid_recreation(
self,
session: AsyncSession,
save_fixture: SaveFixture,
organization: Organization,
customer: Customer,
) -> None:
email = "[email protected]"
customer = await create_customer(
save_fixture,
organization=organization,
email=email,
)
customer = await customer_service.delete(
session,
customer,
)

assert customer.deleted_at is not None
assert customer.email.startswith("deleted.")
assert customer.email.endswith(email)
await session.commit()

recreated = await create_customer(
save_fixture,
organization=organization,
email=email,
)
assert recreated

0 comments on commit 4c6e2b8

Please sign in to comment.