feat: add Remnashop migration import
Add the Remnashop legacy importer, compatibility tables, admin toggles, referral and promo lookup compatibility, and tests for the migration flow.
This commit is contained in:
@@ -44,6 +44,13 @@ BACKUP_SETTINGS = (
|
||||
"BACKUP_COMPOSE_ENABLED",
|
||||
)
|
||||
|
||||
REMNASHOP_MIGRATION_SETTINGS = (
|
||||
"MIGRATION_REMNASHOP_REFERRAL_CODE_COMPAT_ENABLED",
|
||||
"MIGRATION_REMNASHOP_PROMO_CODE_COMPAT_ENABLED",
|
||||
"MIGRATION_REMNASHOP_IMPORTED_AT",
|
||||
"MIGRATION_REMNASHOP_NOTES",
|
||||
)
|
||||
|
||||
ADMIN_TARIFF_SETTINGS_PAGE_KEYS = {
|
||||
"admin_tariffs_trial_title",
|
||||
"admin_tariffs_trial_subtitle",
|
||||
@@ -204,6 +211,27 @@ def test_backup_settings_i18n_keys_exist():
|
||||
assert field["i18n_description_key"] in messages
|
||||
|
||||
|
||||
def test_remnashop_migration_settings_i18n_keys_exist():
|
||||
manifest = _manifest_by_key()
|
||||
|
||||
for setting_key in REMNASHOP_MIGRATION_SETTINGS:
|
||||
field = manifest[setting_key]
|
||||
assert field["section"] == "migrations"
|
||||
assert field["section_order"] == 13
|
||||
assert field["subsection"] == "Remnashop"
|
||||
assert field["i18n_subsection_key"] == "admin_settings_subsection_remnashop"
|
||||
|
||||
for language in ("ru", "en"):
|
||||
messages = _locale(language)
|
||||
|
||||
assert "admin_settings_section_migrations" in messages
|
||||
assert "admin_settings_subsection_remnashop" in messages
|
||||
for setting_key in REMNASHOP_MIGRATION_SETTINGS:
|
||||
field = manifest[setting_key]
|
||||
assert field["i18n_label_key"] in messages
|
||||
assert field["i18n_description_key"] in messages
|
||||
|
||||
|
||||
def test_backup_required_numeric_settings_reject_empty_values():
|
||||
with pytest.raises(ValueError):
|
||||
coerce_value(get_field_by_key("BACKUP_INTERVAL_SECONDS"), "")
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from scripts.import_legacy import (
|
||||
remnashop_months_from_plan_snapshot,
|
||||
remnashop_pricing_amount,
|
||||
remnashop_pricing_currency,
|
||||
remnashop_sale_mode,
|
||||
remnashop_traffic_gb_to_bytes,
|
||||
remnashop_transaction_status,
|
||||
)
|
||||
|
||||
|
||||
def test_remnashop_pricing_helpers_read_final_amount_and_currency():
|
||||
pricing = {"final_amount": "199.50", "currency": "rub"}
|
||||
|
||||
assert remnashop_pricing_amount(pricing) == 199.5
|
||||
assert remnashop_pricing_currency(pricing) == "RUB"
|
||||
|
||||
|
||||
def test_remnashop_traffic_limit_is_converted_from_gib():
|
||||
assert remnashop_traffic_gb_to_bytes(10) == 10 * 1024**3
|
||||
assert remnashop_traffic_gb_to_bytes(None) is None
|
||||
|
||||
|
||||
def test_remnashop_status_and_sale_mode_mapping_matches_current_payment_model():
|
||||
assert remnashop_transaction_status("COMPLETED", "YOOKASSA") == "succeeded"
|
||||
assert remnashop_transaction_status("PENDING", "WATA") == "pending_wata"
|
||||
assert remnashop_transaction_status("CANCELED", "WATA") == "canceled"
|
||||
assert remnashop_sale_mode("NEW") == "subscription"
|
||||
assert remnashop_sale_mode("RENEW") == "subscription"
|
||||
assert remnashop_sale_mode("CHANGE") == "tariff_upgrade"
|
||||
|
||||
|
||||
def test_remnashop_plan_months_prefers_snapshot_then_dates():
|
||||
assert remnashop_months_from_plan_snapshot({"duration_days": 90}) == 3
|
||||
assert remnashop_months_from_plan_snapshot({"months": 12}) == 12
|
||||
assert (
|
||||
remnashop_months_from_plan_snapshot(
|
||||
{},
|
||||
created_at=datetime(2026, 1, 1, tzinfo=timezone.utc),
|
||||
expire_at=datetime(2026, 4, 1, tzinfo=timezone.utc),
|
||||
)
|
||||
== 3
|
||||
)
|
||||
@@ -1,5 +1,11 @@
|
||||
from db.migrator import MIGRATIONS
|
||||
from db.models import SupportTicket, SupportTicketMessage, User
|
||||
from db.models import (
|
||||
LegacyImportMapping,
|
||||
LegacyReferralCode,
|
||||
SupportTicket,
|
||||
SupportTicketMessage,
|
||||
User,
|
||||
)
|
||||
|
||||
|
||||
def test_support_migration_is_registered_after_existing_revisions():
|
||||
@@ -39,3 +45,18 @@ def test_trial_eligibility_reset_migration_and_model_are_registered():
|
||||
"0032_add_telegram_notification_status"
|
||||
)
|
||||
assert "trial_eligibility_reset_at" in User.__table__.columns
|
||||
|
||||
|
||||
def test_legacy_import_compatibility_migration_and_models_are_registered():
|
||||
ids = [migration.id for migration in MIGRATIONS]
|
||||
|
||||
assert "0034_add_legacy_import_compatibility" in ids
|
||||
assert ids.index("0034_add_legacy_import_compatibility") > ids.index(
|
||||
"0033_add_trial_eligibility_reset_marker"
|
||||
)
|
||||
assert User.__table__.columns["referral_code"].type.length == 64
|
||||
assert LegacyReferralCode.__tablename__ == "legacy_referral_codes"
|
||||
assert LegacyImportMapping.__tablename__ == "legacy_import_mappings"
|
||||
assert "uq_legacy_referral_source_code" in {
|
||||
constraint.name for constraint in LegacyReferralCode.__table__.constraints
|
||||
}
|
||||
|
||||
@@ -230,6 +230,8 @@ class UserDalMergeTests(unittest.IsolatedAsyncioTestCase):
|
||||
)
|
||||
self.assertIn("support_ticket_messages", update_tables)
|
||||
self.assertIn("email_verification_codes", delete_tables)
|
||||
self.assertIn("legacy_referral_codes", delete_tables)
|
||||
self.assertIn("legacy_import_mappings", delete_tables)
|
||||
session.delete.assert_awaited_once_with(user)
|
||||
session.flush.assert_awaited_once()
|
||||
|
||||
@@ -366,6 +368,8 @@ class UserDalMergeTests(unittest.IsolatedAsyncioTestCase):
|
||||
self.assertIn("payments", update_tables)
|
||||
self.assertIn("promo_code_activations", update_tables)
|
||||
self.assertIn("user_payment_methods", update_tables)
|
||||
self.assertIn("legacy_referral_codes", update_tables)
|
||||
self.assertIn("legacy_import_mappings", update_tables)
|
||||
self.assertIn("message_logs", update_tables)
|
||||
self.assertIn("users", update_tables)
|
||||
self.assertIn("user_payment_methods", delete_tables)
|
||||
|
||||
Reference in New Issue
Block a user