The wrapper class wasn't properly exposing the app attribute needed for email
sending during payment finalization. This caused AttributeError crashes when
processing real payments. Added explicit app property to ensure proper access.
The sync status request methods were failing due to relative import errors
when trying to import crypto clients. Changed to absolute imports to resolve:
- "attempted relative import beyond top-level package" errors
- Monero and Dogecoin sync status now properly detected
- Payment method availability correctly reflects wallet/node sync status
This restores the intended functionality where crypto payment buttons only
appear when the underlying nodes/wallets are fully synchronized.
- Change Monero is_synced() to simple height > 0 check for remote nodes
- Update get_sync_status() to return appropriate status for remote node setup
- Fixes false "syncing" status when using upstream Monero nodes
- Apply black code formatting for consistency
This preserves the sync status detection functionality while fixing
issues with remote Monero node deployments.
Crypto payment buttons now only appear when nodes are fully synced,
preventing failed payments due to incomplete blockchain synchronization.
- Add is_synced() and get_sync_status() methods to MoneroClient and DogecoinClient
- Add request.monero_synced and request.dogecoin_synced request methods
- Update payment visibility logic to require both enabled AND synced status
- Add helpful sync status messages in checkout template when nodes are syncing
- Prevent customer frustration from unsynchronized payment processing
Payment method visibility now requires:
1. App globally enabled
2. Shop has cold wallet configured
3. RPC accessible and responsive
4. Node/wallet fully synchronized
Auto-sweep functions were not persisting swept_tx_hash to database because
the modified crypto_payment objects weren't being added to the session.
- Add dbsession parameter to auto_sweep_payment functions
- Add explicit dbsession.add(crypto_payment) calls when sweep succeeds
- Update tests to verify swept_tx_hash is set and payment added to session
- Fix existing tests to work with new function signatures
This resolves the issue where swept payments had NULL swept_tx_hash despite
successful fund transfers, which caused infinite processing loops.
- Move CRYPTO.rst to docs/CRYPTO.rst
- Move CRYPTO_PROBLEMS.rst to docs/CRYPTO_PROBLEMS.rst
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add CryptoPayment status constants for cleaner code maintenance
- Add STATUS_EXPIRED_REFUNDED for payments that expired but received funds and were refunded
- Use ACTIVE_STATUSES and TERMINAL_STATUSES for better organization
- Update all status assignments to use constants instead of magic strings
- Fix test expectation for expired_refunded status
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Filter at database level with swept_tx_hash.is_(None) for minimum result set
- Remove artificial "swept" status - keep "confirmed" as final state
- is_swept property derives from swept_tx_hash column, no separate boolean
- Stuck payments with swept_tx_hash set will be automatically excluded
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Replace non-existent is_unlocked_for_user with get_userproduct_for_user check
- Move overpayment refund logic outside elif branch to apply to both new and stuck payments
- All crypto watcher tests now pass
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Exclude already-swept payments from watcher queue to prevent endless processing
- Mark swept payments as "swept" status to remove from future cycles
- Fix cart deactivation by ensuring shop/user objects are attached to session
- Add debug logging for cart deactivation to track behavior
- Resolves issue where confirmed payments were processed every 20 seconds indefinitely
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Formatted Python code using black for:
- crypto_clients.py
- crypto_watcher.py
- test_crypto_watcher.py
Maintains consistent code style across the codebase.
Added test_finalize_invoice_deactivates_cart to verify that when a
cryptocurrency payment is confirmed, the user's active cart is replaced
with a new empty cart.
The test verifies:
- User starts with a non-empty cart
- After finalize_invoice(), user gets a new empty cart
- New cart has different ID than the old cart
This ensures the UX improvement works correctly - users see an empty
cart after their crypto payment is confirmed.
When a cryptocurrency payment is confirmed in finalize_invoice(),
create a new empty cart for the user, mirroring the behavior of
Stripe payments in save_cart().
This ensures users see an empty cart immediately after their crypto
payment is detected on the blockchain, improving the UX by allowing
them to start shopping again instead of seeing the items they just paid for.
- Added logic to get user's current active cart for the shop
- Create new empty cart only if current cart is not empty
- Added logging for debugging
- Mirrors save_cart() behavior used in Stripe checkout flow
Replace urllib with requests library for DogecoinClient HTTP calls:
- Consistent with MoneroClient implementation
- Cleaner code using requests.post() with Basic auth
- Removed unused _headers method and imports
- Both crypto clients now use the same HTTP library
This provides better reliability and consistency across all RPC clients.
Switch from urllib to requests library for all MoneroClient HTTP requests.
The requests library handles Digest authentication correctly while urllib
has compatibility issues with Monero wallet RPC server implementation.
- Simplified code by removing complex urllib Digest auth workarounds
- Uses requests.post() with HTTPDigestAuth for authenticated requests
- Maintains backward compatibility with no-auth configurations
- Adds requests as a runtime dependency for Monero functionality
Fixes Digest authentication issues that caused '401 digest auth failed' errors.
Small fix to help urllib match credentials correctly by adding
both the full RPC URL and base URL to the password manager.
This may resolve Digest authentication issues with Monero wallet RPC.
- Fix crypto_processor.py UUID slicing error by using shop.uuid_str
- Use clean UUID-based label: mps-shop-{uuid}
- Add account tagging with shop name for human identification
- Update development.ini to use environment variables for payment toggles
- Run black formatter on all Python files
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Remove crypto_quote_expiry_seconds operations that were duplicating
what migration 193438acaa95 already added. Only keep payment_risk_threshold columns.
- Added style attribute to bleach allowlist for img tags
- Fixes issue where CSS img { width: 100%; } overrides width attribute
- Inline style='width:360px;' has higher specificity than stylesheet
- Now supports both width='360' and style='width:360px;' formats
- Expand groupr regression test to validate full end-to-end invoice display
- Add proper Stripe key configuration through settings form workflow
- Handle complex transaction management and session state after commits
- Test now produces valid invoice showing coupon discounts for groupr scenario
- Validates both AttributeError fix and invoice template enhancements
- Gracefully handles session/ownership edge cases in checkout completion
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Extended the free coupon checkout test to also verify that:
- Checkout completion creates an invoice with coupon redemptions
- Invoice page displays discount breakdown with coupon information
- Coupon codes and descriptions appear on invoice
- Discount amounts are calculated correctly
This ensures the invoice discount display enhancement works end-to-end.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive pricing breakdown to invoice display showing:
- Subtotal before discounts
- Applied coupon codes and descriptions
- Total discount amount
- Handling costs
- Final total
Critical for ecommerce transparency - both customers and shop owners
can now see what discounts were applied to each invoice.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Remove manual transaction.manager.commit/begin calls that were masking
the real transaction management issues in cart_complete_checkout.
Keep only minimal session re-querying needed for test object attachment.
Now that root cause is fixed, tests can run without transaction workarounds.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Remove manual transaction management (tm.begin/commit) that was conflicting
with pyramid_tm's automatic transaction handling. Keep tm.abort() calls
for proper rollback on payment failures.
Fixes production issue affecting users like groupr and bluediamon during
free cart checkout completion.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Properly handle database state by committing current transaction and
re-querying objects before web interface testing. This fixes database
locking issues while preserving full HTML verification of download button
absence when product has no file.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
The test_product_download_permissions_basic should test real unmocked
behavior to verify download button doesn't appear when no file exists.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add download permissions testing to free coupon checkout regression test
- Create separate basic download permissions test with HTML assertions
- Fix database state management by removing manual user deletion in tearDown
- Update version from 1.0.4 to 1.0.5 for new release
- Validate all three download scenarios:
1. Download permissions work correctly (both tests)
2. Download button appears when file exists (mocked is_ready)
3. Download button absent when no file (unmocked behavior)
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Resolves critical AttributeError in free cart checkout when coupons are applied.
- Fix cart discount calculation cache invalidation in coupon.py
- Add template null safety for active_card in cart_checkout.j2
- Add comprehensive regression test for free cart coupon flow
- Document full defect hunt process in journal.rst
All 87 tests pass. Fixes production crashes during free cart checkout.
- Add test_cart_checkout_logic_with_none_stripe_user_shop to prevent regression
- Tests the exact scenario that caused production AttributeError
- Validates both old buggy code would crash and new fixed code works
- Covers edge case where stripe_user_shop is None in cart checkout
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add null check for stripe_user_shop before accessing active_card property
- Prevents AttributeError: 'NoneType' object has no attribute 'active_card'
- Handle case where stripe_user_shop is None in cart checkout flow
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Replace deprecated .decode("base64") with base64.b64decode() in short_id_to_bytes function
- Add import base64 to meta.py
- Add comprehensive unit tests for short_id_to_bytes and id_to_uuid functions
- Prevents AttributeError: 'str' object has no attribute 'decode' errors
- Resolves bad gateway authentication issues when accessing URLs with short IDs
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Create virtual environment for twine operations instead of system-wide installs
- Use python3 -m build instead of deprecated setup.py commands
- Resolves PEP 668 externally-managed-environment restrictions in CI