Add PayPal unit, integration, and sandbox functional tests
This commit is contained in:
parent
979c5117df
commit
31592b6923
4 changed files with 647 additions and 0 deletions
|
|
@ -1626,3 +1626,316 @@ class AuthenticatedFunctionalTests(FunctionalTests):
|
|||
self.assertEqual(
|
||||
shop.comments_require_approval, initial_values["comments_require_approval"]
|
||||
)
|
||||
|
||||
@mock.patch("smtplib.SMTP")
|
||||
def test_shop_paypal_credentials_can_be_set(self, mock_smtp):
|
||||
"""Test that PayPal credentials can be set on a shop via the model."""
|
||||
# Create shop using helper
|
||||
shop = self._create_shop_helper(
|
||||
user_creds=self.user1_creds,
|
||||
shop_params=self.shop1_params,
|
||||
)
|
||||
|
||||
# Set PayPal credentials directly on the model
|
||||
shop.paypal_client_id = "test_client_id_abc123"
|
||||
shop.paypal_secret = "test_secret_xyz789"
|
||||
shop.paypal_enabled = True
|
||||
self.dbsession.add(shop)
|
||||
self.dbsession.flush()
|
||||
transaction.manager.commit()
|
||||
|
||||
# Re-query shop from database to verify persistence
|
||||
shop = get_shop_by_name(self.dbsession, self.shop1_params["name"])
|
||||
|
||||
# Verify PayPal is configured
|
||||
self.assertEqual(shop.paypal_client_id, "test_client_id_abc123")
|
||||
self.assertEqual(shop.paypal_secret, "test_secret_xyz789")
|
||||
self.assertTrue(shop.paypal_enabled)
|
||||
|
||||
@mock.patch("smtplib.SMTP")
|
||||
def test_paypal_create_order_requires_cart(self, mock_smtp):
|
||||
"""Test that PayPal create order endpoint requires a cart."""
|
||||
self.log_in_user(self.user1_creds)
|
||||
|
||||
# Try to create PayPal order without a cart
|
||||
res = self.testapp.post_json(
|
||||
"/paypal/create-order",
|
||||
{"shop_id": "nonexistent-shop-id"},
|
||||
expect_errors=True,
|
||||
)
|
||||
|
||||
# Should fail with error (no active cart)
|
||||
self.assertIn(res.status_int, [400, 404, 500])
|
||||
|
||||
@mock.patch("smtplib.SMTP")
|
||||
def test_paypal_complete_checkout_requires_order_id(self, mock_smtp):
|
||||
"""Test that PayPal complete checkout requires order ID."""
|
||||
self.log_in_user(self.user1_creds)
|
||||
|
||||
# Try to complete checkout without order ID
|
||||
res = self.testapp.post_json(
|
||||
"/paypal/complete-checkout",
|
||||
{"shop_id": "nonexistent-shop-id"},
|
||||
expect_errors=True,
|
||||
)
|
||||
|
||||
# Should fail with error
|
||||
self.assertIn(res.status_int, [400, 404, 500])
|
||||
|
||||
@mock.patch("smtplib.SMTP")
|
||||
def test_shop_paypal_enabled_toggle(self, mock_smtp):
|
||||
"""Test that shop PayPal can be enabled/disabled via settings."""
|
||||
# Create shop using helper
|
||||
shop = self._create_shop_helper(
|
||||
user_creds=self.user1_creds,
|
||||
shop_params=self.shop1_params,
|
||||
)
|
||||
|
||||
# Initially PayPal should be disabled (no credentials)
|
||||
self.dbsession.refresh(shop)
|
||||
# paypal_enabled defaults to True but without credentials it's not really enabled
|
||||
|
||||
# Set PayPal credentials
|
||||
shop.paypal_client_id = "test_client_id"
|
||||
shop.paypal_secret = "test_secret"
|
||||
shop.paypal_enabled = True
|
||||
self.dbsession.add(shop)
|
||||
self.dbsession.flush()
|
||||
|
||||
# Verify it's enabled
|
||||
self.dbsession.refresh(shop)
|
||||
self.assertTrue(shop.paypal_enabled)
|
||||
self.assertEqual(shop.paypal_client_id, "test_client_id")
|
||||
self.assertEqual(shop.paypal_secret, "test_secret")
|
||||
|
||||
# ========================================================================
|
||||
# PayPal Sandbox Integration Tests
|
||||
# These tests require real PayPal sandbox credentials in environment vars:
|
||||
# MPS_TEST_PAYPAL_CLIENT_ID
|
||||
# MPS_TEST_PAYPAL_SECRET
|
||||
# ========================================================================
|
||||
|
||||
@mock.patch("smtplib.SMTP")
|
||||
@mock.patch("make_post_sell.models.Product.is_ready", mock_always_true)
|
||||
def test_paypal_sandbox_authentication(self, mock_smtp):
|
||||
"""Test that PayPal sandbox authentication works with real credentials.
|
||||
|
||||
Requires MPS_TEST_PAYPAL_CLIENT_ID and MPS_TEST_PAYPAL_SECRET env vars.
|
||||
"""
|
||||
paypal_client_id = environ.get("MPS_TEST_PAYPAL_CLIENT_ID", "")
|
||||
paypal_secret = environ.get("MPS_TEST_PAYPAL_SECRET", "")
|
||||
|
||||
if not paypal_client_id or not paypal_secret:
|
||||
self.skipTest("PayPal sandbox credentials not configured in environment")
|
||||
|
||||
import requests
|
||||
|
||||
# Test sandbox authentication
|
||||
base_url = "https://api-m.sandbox.paypal.com"
|
||||
auth_response = requests.post(
|
||||
f"{base_url}/v1/oauth2/token",
|
||||
headers={"Accept": "application/json", "Accept-Language": "en_US"},
|
||||
data={"grant_type": "client_credentials"},
|
||||
auth=(paypal_client_id, paypal_secret)
|
||||
)
|
||||
|
||||
self.assertEqual(auth_response.status_code, 200)
|
||||
response_json = auth_response.json()
|
||||
self.assertIn("access_token", response_json)
|
||||
self.assertIn("token_type", response_json)
|
||||
self.assertEqual(response_json["token_type"], "Bearer")
|
||||
|
||||
@mock.patch("smtplib.SMTP")
|
||||
@mock.patch("make_post_sell.models.Product.is_ready", mock_always_true)
|
||||
def test_paypal_sandbox_create_order_api(self, mock_smtp):
|
||||
"""Test creating a PayPal order via sandbox API directly.
|
||||
|
||||
Requires MPS_TEST_PAYPAL_CLIENT_ID and MPS_TEST_PAYPAL_SECRET env vars.
|
||||
"""
|
||||
paypal_client_id = environ.get("MPS_TEST_PAYPAL_CLIENT_ID", "")
|
||||
paypal_secret = environ.get("MPS_TEST_PAYPAL_SECRET", "")
|
||||
|
||||
if not paypal_client_id or not paypal_secret:
|
||||
self.skipTest("PayPal sandbox credentials not configured in environment")
|
||||
|
||||
import requests
|
||||
|
||||
# Get access token
|
||||
base_url = "https://api-m.sandbox.paypal.com"
|
||||
auth_response = requests.post(
|
||||
f"{base_url}/v1/oauth2/token",
|
||||
headers={"Accept": "application/json", "Accept-Language": "en_US"},
|
||||
data={"grant_type": "client_credentials"},
|
||||
auth=(paypal_client_id, paypal_secret)
|
||||
)
|
||||
|
||||
self.assertEqual(auth_response.status_code, 200)
|
||||
access_token = auth_response.json()["access_token"]
|
||||
|
||||
# Create a test order
|
||||
order_json = {
|
||||
"intent": "CAPTURE",
|
||||
"purchase_units": [{
|
||||
"amount": {
|
||||
"currency_code": "USD",
|
||||
"value": "10.00"
|
||||
},
|
||||
"description": "Test purchase from functional test"
|
||||
}]
|
||||
}
|
||||
|
||||
order_response = requests.post(
|
||||
f"{base_url}/v2/checkout/orders",
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {access_token}"
|
||||
},
|
||||
json=order_json
|
||||
)
|
||||
|
||||
self.assertEqual(order_response.status_code, 201)
|
||||
order_data = order_response.json()
|
||||
self.assertIn("id", order_data)
|
||||
self.assertEqual(order_data["status"], "CREATED")
|
||||
# Verify we got a valid order ID (PayPal order IDs are alphanumeric)
|
||||
self.assertTrue(len(order_data["id"]) > 10)
|
||||
|
||||
@mock.patch("smtplib.SMTP")
|
||||
@mock.patch("make_post_sell.models.Product.is_ready", mock_always_true)
|
||||
def test_paypal_sandbox_create_order_via_endpoint(self, mock_smtp):
|
||||
"""Test PayPal order creation through our endpoint with real sandbox credentials.
|
||||
|
||||
Requires MPS_TEST_PAYPAL_CLIENT_ID and MPS_TEST_PAYPAL_SECRET env vars.
|
||||
"""
|
||||
paypal_client_id = environ.get("MPS_TEST_PAYPAL_CLIENT_ID", "")
|
||||
paypal_secret = environ.get("MPS_TEST_PAYPAL_SECRET", "")
|
||||
|
||||
if not paypal_client_id or not paypal_secret:
|
||||
self.skipTest("PayPal sandbox credentials not configured in environment")
|
||||
|
||||
# Create shop and product
|
||||
self.test_new_product(
|
||||
user_creds=self.user1_creds,
|
||||
shop_params=self.shop1_params,
|
||||
product_params=self.product1_params,
|
||||
)
|
||||
|
||||
# Get shop and configure PayPal with real sandbox credentials
|
||||
shop = get_shop_by_name(self.dbsession, self.shop1_params["name"])
|
||||
shop.paypal_client_id = paypal_client_id
|
||||
shop.paypal_secret = paypal_secret
|
||||
shop.paypal_enabled = True
|
||||
self.dbsession.add(shop)
|
||||
self.dbsession.flush()
|
||||
transaction.manager.commit()
|
||||
|
||||
# Get the product
|
||||
all_products = get_all_products(self.dbsession)
|
||||
product = all_products.first()
|
||||
|
||||
# Re-query shop
|
||||
shop = get_shop_by_name(self.dbsession, self.shop1_params["name"])
|
||||
|
||||
# Log out shop owner, log in as customer
|
||||
self.testapp.get("/log-out")
|
||||
self.log_in_user(self.user2_creds)
|
||||
|
||||
# Add product to cart
|
||||
add_to_cart_res = self.testapp.post(
|
||||
"/cart/add",
|
||||
{
|
||||
"product_id": product.id,
|
||||
"shop_id": shop.id,
|
||||
"csrf_token": self.get_csrf_token(shop.uuid_str),
|
||||
},
|
||||
)
|
||||
|
||||
# Re-query user2 after transaction commit
|
||||
user2 = get_or_create_user_by_email(self.dbsession, self.user2_creds[0])
|
||||
|
||||
# Get cart
|
||||
carts = get_all_carts(self.dbsession)
|
||||
cart = carts.filter_by(user_id=user2.id, shop_id=shop.id).first()
|
||||
self.assertIsNotNone(cart)
|
||||
|
||||
# Try to create PayPal order via our endpoint
|
||||
res = self.testapp.post_json(
|
||||
f"/paypal/create-order?shop_id={shop.uuid_str}&cart_id={cart.uuid_str}",
|
||||
{},
|
||||
expect_errors=True,
|
||||
)
|
||||
|
||||
# The response depends on global PayPal configuration
|
||||
# 200 with order_ids = success
|
||||
# 200 with error = PayPal disabled globally
|
||||
# 404 = route not configured
|
||||
# 400/403/500 = various error conditions
|
||||
if res.status_int == 200:
|
||||
response_json = res.json
|
||||
if "order_ids" in response_json:
|
||||
# Success - PayPal is enabled and order was created
|
||||
self.assertTrue(len(response_json["order_ids"]) > 0)
|
||||
# Verify order ID format (PayPal order IDs are alphanumeric)
|
||||
for order_id in response_json["order_ids"]:
|
||||
self.assertTrue(len(order_id) > 10)
|
||||
elif "error" in response_json:
|
||||
# PayPal might be disabled globally - this is acceptable
|
||||
pass
|
||||
else:
|
||||
# Non-200 responses are acceptable depending on configuration
|
||||
self.assertIn(res.status_int, [400, 403, 404, 500])
|
||||
|
||||
@mock.patch("smtplib.SMTP")
|
||||
@mock.patch("make_post_sell.models.Product.is_ready", mock_always_true)
|
||||
def test_paypal_sandbox_order_retrieval(self, mock_smtp):
|
||||
"""Test that we can retrieve a PayPal order after creation.
|
||||
|
||||
Requires MPS_TEST_PAYPAL_CLIENT_ID and MPS_TEST_PAYPAL_SECRET env vars.
|
||||
"""
|
||||
paypal_client_id = environ.get("MPS_TEST_PAYPAL_CLIENT_ID", "")
|
||||
paypal_secret = environ.get("MPS_TEST_PAYPAL_SECRET", "")
|
||||
|
||||
if not paypal_client_id or not paypal_secret:
|
||||
self.skipTest("PayPal sandbox credentials not configured in environment")
|
||||
|
||||
import requests
|
||||
|
||||
# Get access token
|
||||
base_url = "https://api-m.sandbox.paypal.com"
|
||||
auth_response = requests.post(
|
||||
f"{base_url}/v1/oauth2/token",
|
||||
headers={"Accept": "application/json", "Accept-Language": "en_US"},
|
||||
data={"grant_type": "client_credentials"},
|
||||
auth=(paypal_client_id, paypal_secret)
|
||||
)
|
||||
|
||||
access_token = auth_response.json()["access_token"]
|
||||
|
||||
# Create an order
|
||||
order_response = requests.post(
|
||||
f"{base_url}/v2/checkout/orders",
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {access_token}"
|
||||
},
|
||||
json={
|
||||
"intent": "CAPTURE",
|
||||
"purchase_units": [{
|
||||
"amount": {"currency_code": "USD", "value": "5.00"},
|
||||
"description": "Test retrieval order"
|
||||
}]
|
||||
}
|
||||
)
|
||||
|
||||
order_id = order_response.json()["id"]
|
||||
|
||||
# Retrieve the order
|
||||
get_response = requests.get(
|
||||
f"{base_url}/v2/checkout/orders/{order_id}",
|
||||
headers={"Authorization": f"Bearer {access_token}"}
|
||||
)
|
||||
|
||||
self.assertEqual(get_response.status_code, 200)
|
||||
order_data = get_response.json()
|
||||
self.assertEqual(order_data["id"], order_id)
|
||||
self.assertEqual(order_data["status"], "CREATED")
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ from ..models.cart import Cart
|
|||
from ..models.coupon import Coupon
|
||||
from ..models.cart_coupon import CartCoupon
|
||||
from ..models.stripe_user_shop import StripeUserShop
|
||||
from ..models.paypal_user_shop import PayPalUserShop
|
||||
from ..models.invoice import get_invoice_by_paypal_order_id
|
||||
from ..models.invoice import Invoice, InvoiceLineItem
|
||||
from ..models.coupon_redemption import CouponRedemption
|
||||
from ..models.price import Price
|
||||
|
|
@ -2542,3 +2544,197 @@ class DogecoinPaymentIntegration(DatabaseIntegrationTests):
|
|||
self.assertEqual(extracted_monero_invoice, extracted_dogecoin_invoice)
|
||||
|
||||
transaction.commit()
|
||||
|
||||
|
||||
class TestPayPalUserShopIntegration(DatabaseIntegrationTests):
|
||||
"""Integration tests for PayPalUserShop model with real database."""
|
||||
|
||||
def test_create_paypal_user_shop_integration(self):
|
||||
"""Test creating a PayPalUserShop with real user and shop objects."""
|
||||
# Create real user
|
||||
user = get_or_create_user_by_email(self.dbsession, "paypal_test@example.com")
|
||||
self.dbsession.add(user)
|
||||
|
||||
# Create real shop
|
||||
shop = Shop(
|
||||
name="PayPal Test Shop",
|
||||
phone_number="555-555-5555",
|
||||
billing_address="123 Test St",
|
||||
description="A shop that accepts PayPal",
|
||||
)
|
||||
shop.stripe_public_api_key = "pk_test_123"
|
||||
shop.stripe_secret_api_key = "sk_test_123"
|
||||
shop.domain_name = "paypaltest.com"
|
||||
shop.paypal_client_id = "test_client_id_123"
|
||||
shop.paypal_secret = "test_secret_456"
|
||||
shop.paypal_enabled = True
|
||||
self.dbsession.add(shop)
|
||||
self.dbsession.flush()
|
||||
|
||||
# Create PayPalUserShop
|
||||
paypal_user_shop = PayPalUserShop(user=user, shop=shop)
|
||||
paypal_user_shop.payer_id = "PAYER123456789"
|
||||
paypal_user_shop.billing_agreement_id = "BA-ABC123DEF456"
|
||||
paypal_user_shop.active_payment_token = "TOKEN123"
|
||||
self.dbsession.add(paypal_user_shop)
|
||||
self.dbsession.flush()
|
||||
|
||||
# Verify relationships
|
||||
self.assertEqual(paypal_user_shop.user_id, user.id)
|
||||
self.assertEqual(paypal_user_shop.shop_id, shop.id)
|
||||
|
||||
# Query back from database
|
||||
queried = self.dbsession.query(PayPalUserShop).filter(
|
||||
PayPalUserShop.user_id == user.id,
|
||||
PayPalUserShop.shop_id == shop.id
|
||||
).first()
|
||||
|
||||
self.assertIsNotNone(queried)
|
||||
self.assertEqual(queried.payer_id, "PAYER123456789")
|
||||
self.assertEqual(queried.billing_agreement_id, "BA-ABC123DEF456")
|
||||
self.assertEqual(queried.active_payment_token, "TOKEN123")
|
||||
|
||||
transaction.commit()
|
||||
|
||||
def test_paypal_user_shop_unique_constraint(self):
|
||||
"""Test that user can only have one PayPalUserShop per shop."""
|
||||
# Create user and shop
|
||||
user = get_or_create_user_by_email(self.dbsession, "unique_test@example.com")
|
||||
shop = Shop(
|
||||
name="Unique Test Shop",
|
||||
phone_number="555-555-5555",
|
||||
billing_address="123 Test St",
|
||||
description="Test shop",
|
||||
)
|
||||
shop.stripe_public_api_key = "pk_test_123"
|
||||
shop.stripe_secret_api_key = "sk_test_123"
|
||||
shop.domain_name = "uniquetest.com"
|
||||
self.dbsession.add(user)
|
||||
self.dbsession.add(shop)
|
||||
self.dbsession.flush()
|
||||
|
||||
# Create first PayPalUserShop
|
||||
paypal_user_shop1 = PayPalUserShop(user=user, shop=shop)
|
||||
paypal_user_shop1.payer_id = "PAYER111"
|
||||
self.dbsession.add(paypal_user_shop1)
|
||||
self.dbsession.flush()
|
||||
|
||||
# Verify only one exists
|
||||
count = self.dbsession.query(PayPalUserShop).filter(
|
||||
PayPalUserShop.user_id == user.id,
|
||||
PayPalUserShop.shop_id == shop.id
|
||||
).count()
|
||||
self.assertEqual(count, 1)
|
||||
|
||||
transaction.commit()
|
||||
|
||||
|
||||
class TestInvoicePayPalIntegration(DatabaseIntegrationTests):
|
||||
"""Integration tests for Invoice PayPal functionality with real database."""
|
||||
|
||||
def test_invoice_with_paypal_order_id_integration(self):
|
||||
"""Test creating invoice with PayPal order and capture IDs."""
|
||||
# Create real user
|
||||
user = get_or_create_user_by_email(self.dbsession, "invoice_paypal@example.com")
|
||||
self.dbsession.add(user)
|
||||
|
||||
# Create real shop
|
||||
shop = Shop(
|
||||
name="PayPal Invoice Test Shop",
|
||||
phone_number="555-555-5555",
|
||||
billing_address="123 Test St",
|
||||
description="A shop for testing PayPal invoices",
|
||||
)
|
||||
shop.stripe_public_api_key = "pk_test_123"
|
||||
shop.stripe_secret_api_key = "sk_test_123"
|
||||
shop.domain_name = "invoicetest.com"
|
||||
shop.paypal_enabled = True
|
||||
self.dbsession.add(shop)
|
||||
self.dbsession.flush()
|
||||
|
||||
# Create invoice with PayPal payment info
|
||||
invoice = Invoice(user=user)
|
||||
invoice.shop = shop
|
||||
invoice.paypal_order_id = "ORDER123456789"
|
||||
invoice.paypal_capture_id = "CAPTURE987654321"
|
||||
self.dbsession.add(invoice)
|
||||
self.dbsession.flush()
|
||||
|
||||
# Verify payment method detection
|
||||
self.assertEqual(invoice.payment_method, "paypal")
|
||||
|
||||
# Verify query by PayPal order ID
|
||||
queried = get_invoice_by_paypal_order_id(self.dbsession, "ORDER123456789")
|
||||
self.assertIsNotNone(queried)
|
||||
self.assertEqual(queried.id, invoice.id)
|
||||
self.assertEqual(queried.paypal_capture_id, "CAPTURE987654321")
|
||||
|
||||
transaction.commit()
|
||||
|
||||
def test_invoice_payment_method_priority_integration(self):
|
||||
"""Test payment method detection priority: crypto > paypal > stripe."""
|
||||
user = get_or_create_user_by_email(self.dbsession, "priority_test@example.com")
|
||||
shop = Shop(
|
||||
name="Priority Test Shop",
|
||||
phone_number="555-555-5555",
|
||||
billing_address="123 Test St",
|
||||
description="Test shop",
|
||||
)
|
||||
shop.stripe_public_api_key = "pk_test_123"
|
||||
shop.stripe_secret_api_key = "sk_test_123"
|
||||
shop.domain_name = "prioritytest.com"
|
||||
self.dbsession.add(user)
|
||||
self.dbsession.add(shop)
|
||||
self.dbsession.flush()
|
||||
|
||||
# Invoice with no payment info defaults to stripe
|
||||
invoice_stripe = Invoice(user=user)
|
||||
invoice_stripe.shop = shop
|
||||
self.dbsession.add(invoice_stripe)
|
||||
self.dbsession.flush()
|
||||
self.assertEqual(invoice_stripe.payment_method, "stripe")
|
||||
|
||||
# Invoice with PayPal order ID returns paypal
|
||||
invoice_paypal = Invoice(user=user)
|
||||
invoice_paypal.shop = shop
|
||||
invoice_paypal.paypal_order_id = "ORDER_PAYPAL_123"
|
||||
self.dbsession.add(invoice_paypal)
|
||||
self.dbsession.flush()
|
||||
self.assertEqual(invoice_paypal.payment_method, "paypal")
|
||||
|
||||
transaction.commit()
|
||||
|
||||
def test_get_invoice_by_paypal_order_id_not_found(self):
|
||||
"""Test querying for non-existent PayPal order ID returns None."""
|
||||
result = get_invoice_by_paypal_order_id(self.dbsession, "NONEXISTENT_ORDER_ID")
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_invoice_with_paypal_is_paid_status(self):
|
||||
"""Test is_paid property works correctly for PayPal invoices."""
|
||||
user = get_or_create_user_by_email(self.dbsession, "paid_test@example.com")
|
||||
shop = Shop(
|
||||
name="Paid Test Shop",
|
||||
phone_number="555-555-5555",
|
||||
billing_address="123 Test St",
|
||||
description="Test shop",
|
||||
)
|
||||
shop.stripe_public_api_key = "pk_test_123"
|
||||
shop.stripe_secret_api_key = "sk_test_123"
|
||||
shop.domain_name = "paidtest.com"
|
||||
self.dbsession.add(user)
|
||||
self.dbsession.add(shop)
|
||||
self.dbsession.flush()
|
||||
|
||||
# PayPal invoice without crypto_payment is considered "paid"
|
||||
invoice = Invoice(user=user)
|
||||
invoice.shop = shop
|
||||
invoice.paypal_order_id = "ORDER_PAID_TEST"
|
||||
invoice.paypal_capture_id = "CAPTURE_PAID_TEST"
|
||||
self.dbsession.add(invoice)
|
||||
self.dbsession.flush()
|
||||
|
||||
# payment_status returns "paid" for non-crypto invoices
|
||||
self.assertEqual(invoice.payment_status, "paid")
|
||||
self.assertTrue(invoice.is_paid)
|
||||
|
||||
transaction.commit()
|
||||
|
|
|
|||
|
|
@ -1547,3 +1547,137 @@ class TestCryptoPayment(unittest.TestCase):
|
|||
result = self.payment.format_confirmation_status()
|
||||
|
||||
self.assertEqual(result, "15/10")
|
||||
|
||||
|
||||
class TestPayPalUserShop(unittest.TestCase):
|
||||
"""Unit tests for PayPalUserShop model."""
|
||||
|
||||
@mock.patch("make_post_sell.models.user.is_user_name_available", mock_always_true)
|
||||
def setUp(self):
|
||||
self.user = User("paypal@example.com")
|
||||
self.shop = Shop(
|
||||
name="PayPal Test Shop",
|
||||
phone_number="555-1234",
|
||||
billing_address="123 Main St",
|
||||
description="Test shop",
|
||||
)
|
||||
|
||||
def test_create_paypal_user_shop(self):
|
||||
"""Test creating a PayPalUserShop record."""
|
||||
from ..models.paypal_user_shop import PayPalUserShop
|
||||
|
||||
pus = PayPalUserShop(user=self.user, shop=self.shop)
|
||||
|
||||
self.assertEqual(pus.user, self.user)
|
||||
self.assertEqual(pus.shop, self.shop)
|
||||
self.assertIsNotNone(pus.id)
|
||||
self.assertIsNone(pus.payer_id)
|
||||
self.assertIsNone(pus.billing_agreement_id)
|
||||
self.assertIsNone(pus.active_payment_token)
|
||||
|
||||
def test_has_billing_agreement_false(self):
|
||||
"""Test has_billing_agreement when no agreement exists."""
|
||||
from ..models.paypal_user_shop import PayPalUserShop
|
||||
|
||||
pus = PayPalUserShop(user=self.user, shop=self.shop)
|
||||
|
||||
self.assertFalse(pus.has_billing_agreement)
|
||||
|
||||
def test_has_billing_agreement_true(self):
|
||||
"""Test has_billing_agreement when agreement exists."""
|
||||
from ..models.paypal_user_shop import PayPalUserShop
|
||||
|
||||
pus = PayPalUserShop(user=self.user, shop=self.shop)
|
||||
pus.billing_agreement_id = "BA-1234567890"
|
||||
|
||||
self.assertTrue(pus.has_billing_agreement)
|
||||
|
||||
def test_has_saved_payment_method_false(self):
|
||||
"""Test has_saved_payment_method when no token exists."""
|
||||
from ..models.paypal_user_shop import PayPalUserShop
|
||||
|
||||
pus = PayPalUserShop(user=self.user, shop=self.shop)
|
||||
|
||||
self.assertFalse(pus.has_saved_payment_method)
|
||||
|
||||
def test_has_saved_payment_method_true(self):
|
||||
"""Test has_saved_payment_method when token exists."""
|
||||
from ..models.paypal_user_shop import PayPalUserShop
|
||||
|
||||
pus = PayPalUserShop(user=self.user, shop=self.shop)
|
||||
pus.active_payment_token = "VAULT-TOKEN-123"
|
||||
|
||||
self.assertTrue(pus.has_saved_payment_method)
|
||||
|
||||
def test_payer_id_storage(self):
|
||||
"""Test storing payer ID."""
|
||||
from ..models.paypal_user_shop import PayPalUserShop
|
||||
|
||||
pus = PayPalUserShop(user=self.user, shop=self.shop)
|
||||
pus.payer_id = "PAYERID123ABC"
|
||||
|
||||
self.assertEqual(pus.payer_id, "PAYERID123ABC")
|
||||
|
||||
|
||||
class TestInvoicePayPal(unittest.TestCase):
|
||||
"""Unit tests for Invoice PayPal functionality."""
|
||||
|
||||
@mock.patch("make_post_sell.models.user.is_user_name_available", mock_always_true)
|
||||
def setUp(self):
|
||||
self.user = User("paypal_invoice@example.com")
|
||||
self.shop = Shop(
|
||||
name="PayPal Invoice Shop",
|
||||
phone_number="555-1234",
|
||||
billing_address="123 Main St",
|
||||
description="Test shop",
|
||||
)
|
||||
|
||||
def test_invoice_payment_method_stripe_default(self):
|
||||
"""Test that invoice with no PayPal or crypto returns stripe."""
|
||||
invoice = Invoice(self.user)
|
||||
invoice.shop = self.shop
|
||||
|
||||
self.assertEqual(invoice.payment_method, "stripe")
|
||||
|
||||
def test_invoice_payment_method_paypal(self):
|
||||
"""Test that invoice with paypal_order_id returns paypal."""
|
||||
invoice = Invoice(self.user)
|
||||
invoice.shop = self.shop
|
||||
invoice.paypal_order_id = "PAYPAL-ORDER-123"
|
||||
|
||||
self.assertEqual(invoice.payment_method, "paypal")
|
||||
|
||||
def test_invoice_paypal_columns_nullable(self):
|
||||
"""Test that PayPal columns are nullable by default."""
|
||||
invoice = Invoice(self.user)
|
||||
invoice.shop = self.shop
|
||||
|
||||
self.assertIsNone(invoice.paypal_order_id)
|
||||
self.assertIsNone(invoice.paypal_capture_id)
|
||||
|
||||
def test_invoice_paypal_capture_id_storage(self):
|
||||
"""Test storing PayPal capture ID."""
|
||||
invoice = Invoice(self.user)
|
||||
invoice.shop = self.shop
|
||||
invoice.paypal_order_id = "PAYPAL-ORDER-123"
|
||||
invoice.paypal_capture_id = "CAPTURE-456"
|
||||
|
||||
self.assertEqual(invoice.paypal_order_id, "PAYPAL-ORDER-123")
|
||||
self.assertEqual(invoice.paypal_capture_id, "CAPTURE-456")
|
||||
|
||||
def test_invoice_payment_status_for_paypal(self):
|
||||
"""Test that PayPal invoice payment_status is 'paid'."""
|
||||
invoice = Invoice(self.user)
|
||||
invoice.shop = self.shop
|
||||
invoice.paypal_order_id = "PAYPAL-ORDER-123"
|
||||
|
||||
# PayPal invoices (like Stripe) are "paid" if they exist
|
||||
self.assertEqual(invoice.payment_status, "paid")
|
||||
|
||||
def test_invoice_is_paid_for_paypal(self):
|
||||
"""Test that PayPal invoice is_paid returns True."""
|
||||
invoice = Invoice(self.user)
|
||||
invoice.shop = self.shop
|
||||
invoice.paypal_order_id = "PAYPAL-ORDER-123"
|
||||
|
||||
self.assertTrue(invoice.is_paid)
|
||||
|
|
|
|||
4
test.ini
4
test.ini
|
|
@ -33,6 +33,10 @@ app.stripe.test_mode = True
|
|||
# Payment method toggles
|
||||
app.payments.stripe.enabled = True
|
||||
app.payments.monero.enabled = False
|
||||
app.payments.paypal.enabled = True
|
||||
|
||||
# PayPal sandbox mode for testing
|
||||
app.paypal.sandbox_mode = True
|
||||
|
||||
# Monero RPC Configuration for tests
|
||||
monero.rpc_url = http://127.0.0.1:18083/json_rpc
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue