Prod previously installed via 'pip install .' (reads unbounded requirements.py3.txt)
plus 'pip install --upgrade -r requirements-prod.txt' — every deploy re-resolved to
whatever PyPI served, unverified. A poisoned release of any dep (stripe, boto3,
sqlalchemy, pyramid...) would land in a payment app.
- requirements-prod.in: source (runtime + prod-server deps)
- requirements-prod.lock: 68 pkgs pinned to exact versions + SHA256 (854 hashes),
generated with uv pip compile --generate-hashes
- install-source-prod now: pip install --require-hashes -r requirements-prod.lock
then pip install --no-deps . — no floating resolve at deploy time
- make pins-lock regenerates the lock deliberately
Validated locally: lock installs under --require-hashes, app imports, 791 logic
tests pass under resolved versions (functional tests need MPS_TEST_* env, gated in CI).
The previous parallel test attempt failed because all workers were trying
to use the same SQLite database file, causing locking errors.
Solution:
- Created conftest.py to configure pytest-xdist workers
- Each worker gets a unique database file (test_make_post_sell_gw0.sqlite, etc.)
- Enabled SQLite WAL (Write-Ahead Logging) mode for better concurrency
- WAL allows multiple readers while a writer is active
- Modified test.ini to use $TEST_DATABASE_PATH environment variable
- Automatic cleanup of worker databases after test completion
Benefits:
- True isolation between test workers
- No database locking conflicts
- Tests can run fully in parallel
- Expected test time reduction from 30min to ~5-10min
Each worker's database is completely isolated, preventing the SQLite
"database is locked" errors that plagued the previous attempt.
The test suite was taking 30 minutes to run sequentially. With 434 tests,
parallel execution should significantly reduce CI time.
Changes:
- Add pytest-xdist to requirements-test.txt
- Update Makefile test target to use 'pytest -n auto'
- Auto mode automatically uses number of CPU cores available
Expected improvements:
- Unit tests and model tests can run fully in parallel
- Integration tests with isolated databases can run in parallel
- Overall test time should reduce to ~5-10 minutes on multi-core CI
Note: Crypto RPC tests may still be a bottleneck if they hit shared
wallet daemons, but most other tests should parallelize well.
- Convert all state names from underscore to dash format in markdown documentation
- Ensures consistency across all documentation formats (dot, svg, markdown)
- All payment states now use dashes: confirmed-complete, underpaid-refunded, etc.
- Maintains consistency with the source dot file which is the canonical reference
This completes the documentation naming convention standardization.
- Add payment amount to shop output for overpayment refunds
- Both XMR and DOGE now send payment + restocking fee to shop
- Fix insufficient funds error by using conservative fee buffer (0.01 DOGE)
- Round outputs down to 3 decimal places to avoid precision issues
- Update sendmany to try actual account first (where funds are located)
- Add better error handling for different account formats
- Fix fee calculation to properly account for Dogecoin's fee-on-top model
The issue was that sendmany adds network fee on top of outputs, and we
were trying to send exactly the wallet balance, leaving no room for fees.
Now we reserve 0.01 DOGE for fees and round conservatively.
- Remove error messages from sweep/sweep-check Makefile targets
- Keep commands functional for developers/admins in local environments
- Simplify documentation to focus on automatic sweeping behavior
- Maintain separation between end-user docs and dev tools
- Remove config modification logic from make serve to respect existing listen settings
- Remove --reload flag to test remote host binding
- Add missing listsinceblock method to DogecoinClient and MockDogecoinClient for late payment scanning
- Update Dogecoin auto sweep test expectations to match new 0.002 DOGE fee buffer (was 0.1 DOGE)
Use pserve config override syntax: listen=0.0.0.0:6501
instead of invalid --bind flag. This forces the server to bind
to all interfaces on port 6501 for external access during development.
The --reload flag was ignoring the listen = 0.0.0.0:6501 setting
in development.ini. Added explicit --bind=0.0.0.0:6501 to make serve
target to ensure development server binds to all interfaces on port 6501.
This allows external access to the dev server for testing.
1. Added getblockhash() method to DogecoinClient for late payment scanning
- Fixes 'DogecoinClient' object has no attribute 'getblockhash' error
- Required for crypto watcher to scan for missed payments
2. Added sweep-all-doge Makefile target for dust collection
- Sweeps ALL spendable Dogecoin balance to cold storage
- Uses sendtoaddress with subtractfeefromamount=true for complete sweep
- Includes safety confirmations and balance checks
- Perfect for cleaning up dust from hot wallet
Usage:
COLD_WALLET_ADDRESS=DYourColdAddress make sweep-all-doge
Critical for production Dogecoin deployment and hot wallet management.
- Add UserCryptoRefundAddress import and lookup function
- Update _create_duplicate_payment to lookup saved refund address
- Fix refund processing to check saved addresses if not set on payment
- Add test for refund address inheritance
- Add Makefile target for sweeping all wallet funds (sweep-all)
This fixes the issue where duplicate payments weren't being refunded
because they had no refund_address set. Now the system will:
1. First check if original payment has refund_address
2. If not, lookup user's saved refund address for that coin type
3. Use the found address for the duplicate payment record
Also added sweep-all target to collect dust from all accounts.
- Add terminal -complete status enums for all refund types
- Update crypto watcher to transition refunds to complete status at 10+ confirmations
- Fix cancelled payment quote viewing with proper access control and USD calculation
- Update status mappings and templates to support complete statuses
- Move payment status display to breakdown section in checkout template
- Add View Quote buttons for cancelled and refunded payments
🤖 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.
Dead man switch activated. Good luck everyone, I wish you the best.
- BDFL
new file: .gitignore
new file: MANIFEST.in
new file: Makefile
new file: README.rst
new file: development.ini
new file: journal.rst
new file: make_post_sell/__init__.py
new file: make_post_sell/config_jinja2.py
new file: make_post_sell/lib/__init__.py
new file: make_post_sell/lib/mail.py
new file: make_post_sell/lib/mail_messages.py
new file: make_post_sell/lib/render.py
new file: make_post_sell/models/__init__.py
new file: make_post_sell/models/cart.py
new file: make_post_sell/models/cart_coupon.py
new file: make_post_sell/models/coupon.py
new file: make_post_sell/models/coupon_redemption.py
new file: make_post_sell/models/invoice.py
new file: make_post_sell/models/market.py
new file: make_post_sell/models/meta.py
new file: make_post_sell/models/price.py
new file: make_post_sell/models/product.py
new file: make_post_sell/models/shop.py
new file: make_post_sell/models/shop_search_request.py
new file: make_post_sell/models/stripe_user_shop.py
new file: make_post_sell/models/user.py
new file: make_post_sell/models/user_product.py
new file: make_post_sell/models/user_shop.py
new file: make_post_sell/request_methods.py
new file: make_post_sell/routes.py
new file: make_post_sell/scripts/__init__.py
new file: make_post_sell/scripts/alembic/README
new file: make_post_sell/scripts/alembic/env.py
new file: make_post_sell/scripts/alembic/script.py.mako
new file: make_post_sell/scripts/alembic/versions/15751f5d7a03_add_active_cart_total_in_cents_to_user_.py
new file: make_post_sell/scripts/alembic/versions/24662905655f_create_new_active_shop_id_column_on_.py
new file: make_post_sell/scripts/alembic/versions/3e1e70bfe89d_google_analytics_id.py
new file: make_post_sell/scripts/alembic/versions/4d9da43b0e86_product_visibility_column.py
new file: make_post_sell/scripts/alembic/versions/5c40dfb56179_shop_ribbon_columns.py
new file: make_post_sell/scripts/alembic/versions/6da97f2f913f_add_updated_timestamp_to_cart.py
new file: make_post_sell/scripts/alembic/versions/96f851cbab01_terms_and_privacy.py
new file: make_post_sell/scripts/alembic/versions/ab7338eaedf1_add_price_in_cents_column.py
new file: make_post_sell/scripts/alembic/versions/af28cc35ed6f_product_bundles.py
new file: make_post_sell/scripts/alembic/versions/b0d5604d9255_add_active_cart_count_to_user_table.py
new file: make_post_sell/scripts/alembic/versions/bfc4195a7f56_product_is_sellable_coluumn.py
new file: make_post_sell/scripts/alembic/versions/c4d5566ec87d_coupon_stackable_and_couponredemption.py
new file: make_post_sell/scripts/alembic/versions/e12bbe39d87e_cart_coupon_table.py
new file: make_post_sell/scripts/alembic/versions/eadd0d69e133_shop_ribbon_text_color.py
new file: make_post_sell/scripts/alembic/versions/f3aa57777025_coupon_table.py
new file: make_post_sell/scripts/alembic/versions/f882f2255cd1_add_stripe_secret_and_public_key_to_shop.py
new file: make_post_sell/scripts/alembic/versions/fd9f7e2f2b78_user_full_name.py
new file: make_post_sell/scripts/initialize_db.py
new file: make_post_sell/scripts/pshell.py
new file: make_post_sell/static/css/alerts.css
new file: make_post_sell/static/css/common.css
new file: make_post_sell/static/css/lib.css
new file: make_post_sell/static/css/mps.css
new file: make_post_sell/static/favicon.ico
new file: make_post_sell/static/js/custom.js
new file: make_post_sell/static/js/jquery-3.4.1.min.js
new file: make_post_sell/static/js/jquery.min.js
new file: make_post_sell/static/makepostsell-3.png
new file: make_post_sell/static/makepostsell.png
new file: make_post_sell/static/mps.png
new file: make_post_sell/templates/actions_new.j2
new file: make_post_sell/templates/actions_view.j2
new file: make_post_sell/templates/base.j2
new file: make_post_sell/templates/billing.j2
new file: make_post_sell/templates/cart.j2
new file: make_post_sell/templates/cart_checkout.j2
new file: make_post_sell/templates/carts.j2
new file: make_post_sell/templates/content.j2
new file: make_post_sell/templates/content_new.j2
new file: make_post_sell/templates/coupon.j2
new file: make_post_sell/templates/coupon_new.j2
new file: make_post_sell/templates/coupons.j2
new file: make_post_sell/templates/home.j2
new file: make_post_sell/templates/join-or-log-in.j2
new file: make_post_sell/templates/markup_editor.j2
new file: make_post_sell/templates/markup_renderer.j2
new file: make_post_sell/templates/product.j2
new file: make_post_sell/templates/product_edit.j2
new file: make_post_sell/templates/product_new.j2
new file: make_post_sell/templates/products.j2
new file: make_post_sell/templates/shop.j2
new file: make_post_sell/templates/shop_about.j2
new file: make_post_sell/templates/shop_new.j2
new file: make_post_sell/templates/shop_products.j2
new file: make_post_sell/templates/shop_settings.j2
new file: make_post_sell/templates/shops.j2
new file: make_post_sell/templates/snippets/csrf.j2
new file: make_post_sell/templates/snippets/flash-alerts.j2
new file: make_post_sell/templates/snippets/google-analytics.j2
new file: make_post_sell/templates/snippets/optional-javascript.j2
new file: make_post_sell/templates/snippets/ribbon.j2
new file: make_post_sell/templates/snippets/search.j2
new file: make_post_sell/templates/snippets/stripe.j2
new file: make_post_sell/templates/update-card.j2
new file: make_post_sell/templates/user_settings.j2
new file: make_post_sell/tests/__init__.py
new file: make_post_sell/tests/test_functional.py
new file: make_post_sell/tests/test_models.py
new file: make_post_sell/views/__init__.py
new file: make_post_sell/views/actions.py
new file: make_post_sell/views/authentication.py
new file: make_post_sell/views/billing.py
new file: make_post_sell/views/cart.py
new file: make_post_sell/views/content.py
new file: make_post_sell/views/coupon.py
new file: make_post_sell/views/misc.py
new file: make_post_sell/views/product.py
new file: make_post_sell/views/shop.py
new file: make_post_sell/views/user.py
new file: pytest.ini
new file: requirements-dev.txt
new file: requirements-prod.txt
new file: requirements-test.txt
new file: requirements.py3.txt
new file: requirements.txt
new file: setup.py
new file: test.ini