test_integration: align with current payment schema and code

Rewrite the integration tests against the current schema/behaviour:
- crypto flow: process_transaction records the tx itself (drop the manual
  crypto_transactions insert with non-existent from_address/to_address columns;
  ensure a crypto wallet row exists; pass a float amount for SQLite binding).
- subscriptions: use account_tiers + subscriptions (not subscription_tiers/
  user_subscriptions), create the required card payment method, and make the
  renewal subscription actually due (current_period_end in the past); assert via
  process_renewals' processed count.
- consolidation: enable crypto_consolidation_settings so candidates are queued.
- notifications: enable email_notification_settings and add an email_templates
  row so the notification is actually sent.
Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
parent eee8b347
...@@ -183,14 +183,14 @@ class TestCryptoPaymentFlow: ...@@ -183,14 +183,14 @@ class TestCryptoPaymentFlow:
# Create address # Create address
address = await payment_service.wallet_manager.get_or_create_user_address(1, 'btc') address = await payment_service.wallet_manager.get_or_create_user_address(1, 'btc')
# Simulate incoming transaction # Ensure a crypto wallet row exists so the confirmed credit can update it
# (process_transaction records the crypto_transactions row itself).
with db_manager._get_connection() as conn: with db_manager._get_connection() as conn:
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute(""" cursor.execute("""
INSERT INTO crypto_transactions INSERT OR IGNORE INTO user_crypto_wallets (user_id, crypto_type, balance_crypto, balance_fiat)
(user_id, crypto_type, tx_hash, from_address, to_address, amount_crypto, confirmations, status) VALUES (1, 'btc', 0, 0)
VALUES (1, 'btc', 'test_tx_hash', 'sender_addr', ?, 0.001, 3, 'pending') """)
""", (address,))
conn.commit() conn.commit()
# Process transaction (simulate blockchain monitor) # Process transaction (simulate blockchain monitor)
...@@ -200,7 +200,7 @@ class TestCryptoPaymentFlow: ...@@ -200,7 +200,7 @@ class TestCryptoPaymentFlow:
tx_hash='test_tx_hash', tx_hash='test_tx_hash',
from_address='sender_addr', from_address='sender_addr',
to_address=address, to_address=address,
amount=Decimal('0.001'), amount=0.001,
confirmations=3 confirmations=3
) )
...@@ -223,16 +223,19 @@ class TestSubscriptionFlow: ...@@ -223,16 +223,19 @@ class TestSubscriptionFlow:
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_create_subscription(self, payment_service, db_manager): async def test_create_subscription(self, payment_service, db_manager):
"""Test creating a subscription""" """Test creating a subscription"""
# Create tier # Create tier (account_tiers) and a card payment method for the user.
with db_manager._get_connection() as conn: with db_manager._get_connection() as conn:
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute(""" cursor.execute("""
INSERT INTO subscription_tiers INSERT INTO account_tiers (name, price_monthly, price_yearly, is_active)
(name, price_monthly, price_yearly, features_json, is_active) VALUES ('Pro', 10.00, 100.00, 1)
VALUES ('Pro', 10.00, 100.00, '{}', 1)
""") """)
conn.commit()
tier_id = cursor.lastrowid tier_id = cursor.lastrowid
cursor.execute("""
INSERT INTO payment_methods (id, user_id, type, identifier, is_default, is_active)
VALUES (1, 1, 'card', 'tok_visa', 1, 1)
""")
conn.commit()
# Create subscription # Create subscription
result = await payment_service.subscription_manager.create_subscription( result = await payment_service.subscription_manager.create_subscription(
...@@ -245,13 +248,10 @@ class TestSubscriptionFlow: ...@@ -245,13 +248,10 @@ class TestSubscriptionFlow:
assert result['success'] is True assert result['success'] is True
assert 'subscription_id' in result assert 'subscription_id' in result
# Verify subscription in database # Verify subscription in database (subscriptions, not user_subscriptions)
with db_manager._get_connection() as conn: with db_manager._get_connection() as conn:
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute(""" cursor.execute("SELECT status FROM subscriptions WHERE user_id = 1")
SELECT status FROM user_subscriptions
WHERE user_id = 1
""")
row = cursor.fetchone() row = cursor.fetchone()
assert row is not None assert row is not None
...@@ -260,37 +260,32 @@ class TestSubscriptionFlow: ...@@ -260,37 +260,32 @@ class TestSubscriptionFlow:
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_subscription_renewal(self, payment_service, db_manager): async def test_subscription_renewal(self, payment_service, db_manager):
"""Test subscription renewal process""" """Test subscription renewal process"""
# Create tier and subscription # Create tier, payment method, and a subscription that is already due.
with db_manager._get_connection() as conn: with db_manager._get_connection() as conn:
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute(""" cursor.execute("""
INSERT INTO subscription_tiers INSERT INTO account_tiers (name, price_monthly, price_yearly, is_active)
(name, price_monthly, price_yearly, features_json, is_active) VALUES ('Pro', 10.00, 100.00, 1)
VALUES ('Pro', 10.00, 100.00, '{}', 1)
""") """)
tier_id = cursor.lastrowid tier_id = cursor.lastrowid
# Create subscription expiring soon
cursor.execute(""" cursor.execute("""
INSERT INTO user_subscriptions INSERT INTO payment_methods (id, user_id, type, identifier, gateway, is_default, is_active)
(user_id, tier_id, status, billing_cycle, next_billing_date, payment_method_id) VALUES (1, 1, 'card', 'tok_visa', 'stripe', 1, 1)
VALUES (1, ?, 'active', 'monthly', date('now', '+1 day'), 1) """)
# current_period_end in the past so the renewal is due
cursor.execute("""
INSERT INTO subscriptions
(user_id, tier_id, payment_method_id, status, billing_cycle,
current_period_start, current_period_end)
VALUES (1, ?, 1, 'active', 'monthly', datetime('now', '-31 days'), datetime('now', '-1 day'))
""", (tier_id,)) """, (tier_id,))
conn.commit() conn.commit()
# Process renewals # Process renewals
await payment_service.renewal_processor.process_renewals() result = await payment_service.renewal_processor.process_renewals()
# Verify renewal was attempted
with db_manager._get_connection() as conn:
cursor = conn.cursor()
cursor.execute("""
SELECT COUNT(*) FROM subscription_billing_history
WHERE user_id = 1
""")
count = cursor.fetchone()[0]
assert count > 0 # The due subscription should have been picked up and processed.
assert result['processed'] >= 1
class TestWalletConsolidation: class TestWalletConsolidation:
...@@ -310,19 +305,30 @@ class TestWalletConsolidation: ...@@ -310,19 +305,30 @@ class TestWalletConsolidation:
with db_manager._get_connection() as conn: with db_manager._get_connection() as conn:
cursor = conn.cursor() cursor = conn.cursor()
# Enable consolidation for btc with a threshold below the balance
cursor.execute("""
INSERT INTO crypto_consolidation_settings
(crypto_type, threshold_amount, admin_address, is_enabled)
VALUES ('btc', 1.0, 'admin_btc_address', 1)
""")
# Create address # Create address
cursor.execute(""" cursor.execute("""
INSERT INTO user_crypto_addresses INSERT OR IGNORE INTO user_crypto_addresses
(user_id, crypto_type, address, derivation_path, derivation_index) (user_id, crypto_type, address, derivation_path, derivation_index)
VALUES (1, 'btc', 'user_btc_address', 'm/44/0/0/0/0', 0) VALUES (1, 'btc', 'user_btc_address', 'm/44/0/0/0/0', 0)
""") """)
# Create wallet with high balance # Create wallet with high balance
cursor.execute(""" cursor.execute("""
INSERT INTO user_crypto_wallets INSERT OR IGNORE INTO user_crypto_wallets
(user_id, crypto_type, balance_crypto, balance_fiat) (user_id, crypto_type, balance_crypto, balance_fiat)
VALUES (1, 'btc', 1.5, 50000.00) VALUES (1, 'btc', 1.5, 50000.00)
""") """)
cursor.execute("""
UPDATE user_crypto_wallets SET balance_crypto = 1.5, balance_fiat = 50000.00
WHERE user_id = 1 AND crypto_type = 'btc'
""")
conn.commit() conn.commit()
...@@ -351,7 +357,7 @@ class TestEmailNotifications: ...@@ -351,7 +357,7 @@ class TestEmailNotifications:
email_service = EmailNotificationService(db_manager) email_service = EmailNotificationService(db_manager)
# Configure SMTP (mock) # Configure SMTP plus enable the notification type and provide a template.
with db_manager._get_connection() as conn: with db_manager._get_connection() as conn:
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute(""" cursor.execute("""
...@@ -359,6 +365,14 @@ class TestEmailNotifications: ...@@ -359,6 +365,14 @@ class TestEmailNotifications:
(smtp_host, smtp_port, smtp_username, smtp_password, from_email, from_name, use_tls) (smtp_host, smtp_port, smtp_username, smtp_password, from_email, from_name, use_tls)
VALUES ('smtp.test.com', 587, 'test', 'pass', 'noreply@test.com', 'Test', 1) VALUES ('smtp.test.com', 587, 'test', 'pass', 'noreply@test.com', 'Test', 1)
""") """)
cursor.execute("""
INSERT INTO email_notification_settings (notification_type, is_enabled, subject_template)
VALUES ('payment_success', 1, 'Payment received')
""")
cursor.execute("""
INSERT INTO email_templates (notification_type, template_html, template_text)
VALUES ('payment_success', '<p>Thank you for your payment.</p>', 'Thank you for your payment.')
""")
conn.commit() conn.commit()
# Mock SMTP # Mock SMTP
...@@ -461,33 +475,28 @@ class TestEndToEndFlow: ...@@ -461,33 +475,28 @@ class TestEndToEndFlow:
address = await payment_service.wallet_manager.get_or_create_user_address(1, 'btc') address = await payment_service.wallet_manager.get_or_create_user_address(1, 'btc')
assert address is not None assert address is not None
# 2. Simulate incoming payment # 2. Simulate a confirmed crypto deposit crediting the wallet
with db_manager._get_connection() as conn: with db_manager._get_connection() as conn:
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute(""" cursor.execute("""
INSERT INTO crypto_transactions INSERT OR IGNORE INTO user_crypto_wallets
(user_id, crypto_type, tx_hash, from_address, to_address, amount_crypto, confirmations, status)
VALUES (1, 'btc', 'tx_001', 'sender', ?, 0.01, 3, 'confirmed')
""", (address,))
# Credit wallet
cursor.execute("""
INSERT INTO user_crypto_wallets
(user_id, crypto_type, balance_crypto, balance_fiat) (user_id, crypto_type, balance_crypto, balance_fiat)
VALUES (1, 'btc', 0.01, 500.00) VALUES (1, 'btc', 0.01, 500.00)
""") """)
conn.commit() conn.commit()
# 3. Create subscription tier # 3. Create subscription tier and a card payment method
with db_manager._get_connection() as conn: with db_manager._get_connection() as conn:
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute(""" cursor.execute("""
INSERT INTO subscription_tiers INSERT INTO account_tiers (name, price_monthly, price_yearly, is_active)
(name, price_monthly, price_yearly, features_json, is_active) VALUES ('Pro', 10.00, 100.00, 1)
VALUES ('Pro', 10.00, 100.00, '{}', 1)
""") """)
tier_id = cursor.lastrowid tier_id = cursor.lastrowid
cursor.execute("""
INSERT INTO payment_methods (id, user_id, type, identifier, is_default, is_active)
VALUES (1, 1, 'card', 'tok_visa', 1, 1)
""")
conn.commit() conn.commit()
# 4. Create subscription # 4. Create subscription
...@@ -503,9 +512,7 @@ class TestEndToEndFlow: ...@@ -503,9 +512,7 @@ class TestEndToEndFlow:
# 5. Verify subscription active # 5. Verify subscription active
with db_manager._get_connection() as conn: with db_manager._get_connection() as conn:
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute(""" cursor.execute("SELECT status FROM subscriptions WHERE user_id = 1")
SELECT status FROM user_subscriptions WHERE user_id = 1
""")
status = cursor.fetchone()[0] status = cursor.fetchone()[0]
assert status == 'active' assert status == 'active'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment