Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: make initial deposit backfill defensive against subsidy-less ledgers #271

Merged
merged 1 commit into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,23 @@
Note this has no reverse migration logic. Attempts to rollback the deployment which includes this PR will not delete
(un-backfill) the deposits created during the forward migration.
"""
import logging

import django.utils.timezone
from django.db import migrations

from enterprise_subsidy.apps.subsidy.migration_utils import find_legacy_initial_transactions
from enterprise_subsidy.apps.subsidy.models import SubsidyReferenceChoices

logger = logging.getLogger(__name__)


def forwards_func(apps, schema_editor):
"""
The core logic of this migration.
"""
# We get the models from the versioned app registry; if we directly import it, it'll be the wrong version.
Ledger = apps.get_model("openedx_ledger", "Ledger")
Transaction = apps.get_model("openedx_ledger", "Transaction")
Deposit = apps.get_model("openedx_ledger", "Deposit")
HistoricalDeposit = apps.get_model("openedx_ledger", "HistoricalDeposit")
Expand All @@ -44,12 +49,22 @@ def forwards_func(apps, schema_editor):
deposits_to_backfill = []
historical_deposits_to_backfill = []
for tx in legacy_initial_transactions:
sales_contract_reference_id = None
sales_contract_reference_provider = None
try:
sales_contract_reference_id = tx.ledger.subsidy.reference_id
sales_contract_reference_provider = sales_contract_reference_providers[tx.ledger.subsidy.reference_type]
except Ledger.subsidy.RelatedObjectDoesNotExist:
logger.warning(
"Found a ledger (%s) without a related subsidy, so the initial deposit will not have a sales contract.",
tx.ledger.uuid,
)
deposit_fields = {
"ledger": tx.ledger,
"transaction": tx,
"desired_deposit_quantity": tx.quantity,
"sales_contract_reference_id": tx.ledger.subsidy.reference_id,
"sales_contract_reference_provider": sales_contract_reference_providers[tx.ledger.subsidy.reference_type],
"sales_contract_reference_id": sales_contract_reference_id,
"sales_contract_reference_provider": sales_contract_reference_provider,
}
deposit = Deposit(**deposit_fields)
historical_deposit = HistoricalDeposit(
Expand Down
66 changes: 43 additions & 23 deletions enterprise_subsidy/apps/subsidy/tests/test_migrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,22 @@

@pytest.mark.django_db
@pytest.mark.parametrize(
"initial_deposit_exists,subsidy_reference_id",
"initial_deposit_exists,subsidy_exists,subsidy_reference_id",
[
(False, None),
(False, "abc123"),
(True, None),
(True, "abc123"),
(False, False, None),
(False, True, None),
(False, True, "abc123"),
(True, False, None),
(True, True, None),
(True, True, "abc123"),
],
)
def test_migration_0022_backfill_initial_deposits(migrator, initial_deposit_exists, subsidy_reference_id):
def test_migration_0022_backfill_initial_deposits(
migrator,
initial_deposit_exists,
subsidy_exists,
subsidy_reference_id,
):
"""
Test Backfilling initial deposits via data migration.
"""
Expand All @@ -36,23 +43,27 @@ def test_migration_0022_backfill_initial_deposits(migrator, initial_deposit_exis
SalesContractReferenceProvider = old_state.apps.get_model("openedx_ledger", "SalesContractReferenceProvider")

ledger = Ledger.objects.create()
subsidy = Subsidy.objects.create(
ledger=ledger,
starting_balance=100,
reference_id=subsidy_reference_id,
enterprise_customer_uuid=uuid.uuid4(),
)
subsidy = None
if subsidy_exists:
subsidy = Subsidy.objects.create(
ledger=ledger,
starting_balance=100,
reference_id=subsidy_reference_id,
enterprise_customer_uuid=uuid.uuid4(),
)
transaction = Transaction.objects.create(
ledger=ledger,
idempotency_key=INITIAL_DEPOSIT_TRANSACTION_SLUG,
quantity=subsidy.starting_balance,
quantity=subsidy.starting_balance if subsidy_exists else 100,
state=TransactionStateChoices.COMMITTED
)
if initial_deposit_exists:
sales_contract_reference_provider = SalesContractReferenceProvider.objects.create(
slug=subsidy.reference_type,
name="Foo Bar",
)
sales_contract_reference_provider = None
if subsidy_exists:
sales_contract_reference_provider = SalesContractReferenceProvider.objects.create(
slug=subsidy.reference_type,
name="Foo Bar",
)
Deposit.objects.create(
ledger=ledger,
desired_deposit_quantity=transaction.quantity,
Expand Down Expand Up @@ -83,14 +94,23 @@ def test_migration_0022_backfill_initial_deposits(migrator, initial_deposit_exis

# Finally check that all the deposit values are correct.
assert Deposit.objects.first().ledger.uuid == ledger.uuid
assert Deposit.objects.first().desired_deposit_quantity == subsidy.starting_balance
assert Deposit.objects.first().desired_deposit_quantity == 100
assert Deposit.objects.first().transaction.uuid == transaction.uuid
assert Deposit.objects.first().sales_contract_reference_id == subsidy_reference_id
assert Deposit.objects.first().sales_contract_reference_provider.slug == subsidy.reference_type
if subsidy_exists:
assert Deposit.objects.first().sales_contract_reference_id == subsidy_reference_id
assert Deposit.objects.first().sales_contract_reference_provider.slug == subsidy.reference_type
else:
assert Deposit.objects.first().sales_contract_reference_id is None
assert Deposit.objects.first().sales_contract_reference_provider is None

assert HistoricalDeposit.objects.first().ledger.uuid == ledger.uuid
assert HistoricalDeposit.objects.first().desired_deposit_quantity == subsidy.starting_balance
assert HistoricalDeposit.objects.first().desired_deposit_quantity == 100
assert HistoricalDeposit.objects.first().transaction.uuid == transaction.uuid
assert HistoricalDeposit.objects.first().sales_contract_reference_id == subsidy_reference_id
assert HistoricalDeposit.objects.first().sales_contract_reference_provider.slug == subsidy.reference_type
if subsidy_exists:
assert HistoricalDeposit.objects.first().sales_contract_reference_id == subsidy_reference_id
assert HistoricalDeposit.objects.first().sales_contract_reference_provider.slug == subsidy.reference_type
else:
assert HistoricalDeposit.objects.first().sales_contract_reference_id is None
assert HistoricalDeposit.objects.first().sales_contract_reference_provider is None
assert HistoricalDeposit.objects.first().history_type == "+"
assert HistoricalDeposit.objects.first().history_change_reason == "Data migration to backfill initial deposits"
Loading