Dev#2
Open
liuyulin-1024 wants to merge 13 commits into
Open
Conversation
Add db field mapping to each parameter in api_test.html, showing the corresponding database table.column (e.g. payments.merchant_order_no, subscriptions.plan_id) next to each form field. Also add k8s deployment manifests for gateway, prod config, and target group binding. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add payment_method and payment_options fields to CreatePaymentRequest, with schema-level validation (currency whitelist for alipay, client option for wechat_pay) and Stripe adapter logic to conditionally set payment_method_options and skip payment_intent_data for wechat_pay. Fallback to card is now restricted to implicit method scenarios only. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…scriptions Implement Worker-driven recurring billing lifecycle for payment methods that lack native subscription support. Includes renewal scanning, grace period enforcement, reminder re-delivery, and automatic refund for duplicate/race-condition payments. Key fixes applied during review: - Keep SubscriptionResponse.plan as required field with fallback - Auto-refund on idempotent renewal skip (prevents silent money loss) - Deterministic webhook event_id with attempt suffix for reminders - Grace period base uses max(period_end, now) to prevent shrinkage - Fix hmac.new → hmac.HMAC for webhook signature Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The python-dateutil dependency was added to pyproject.toml but the lock file was not regenerated, causing ModuleNotFoundError in Docker builds. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…payloads Add payment_method field to subscription webhook and checkout_expires_at to renewal webhooks for downstream consumers. Reorganize k8s configs into dev/prod subdirectories and add dev environment deployment manifests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…lnerabilities - mako 1.3.10 → 1.3.12 (CVE-2026-44307, CVE-2026-41205 path traversal) - python-dotenv 1.2.1 → 1.2.2 (CVE-2026-28684 symlink following) - requests 2.32.5 → 2.33.1 (CVE-2026-25645 insecure temp file) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Stripe wechat_pay only accepts CNY/HKD as Checkout Session currency, but
hub had no upfront guard — sending a USD plan to /v1/subscriptions with
payment_method=wechat_pay reached Stripe and bubbled up an opaque 4xx.
Mirror the existing alipay validation: reject the request at the schema
level (CreatePaymentRequest) and at the service level
(SubscriptionService.create_subscription) with code 4006 so callers see a
deterministic error and never hit the gateway.
- Add WECHAT_PAY_SUPPORTED_CURRENCIES = {"CNY", "HKD"} alongside the
existing alipay set in core.constants.
- Plumb the new validator into both code paths (Pydantic + service).
- Realign two existing tests that fixtured a default USD plan with a
wechat_pay payment method (would now trip the guard).
…ovider Two related gaps in the email lifecycle of subscription checkout: 1. App-managed checkout (alipay / wechat_pay) skips Stripe Customer binding and uses mode=payment Sessions. Stripe pre-fills the email field from session.customer_email, but SubscriptionService never put the user-supplied email there — the hosted page always rendered an empty input. Forward req.email through metadata.customer_email so StripeAdapter.create_payment can populate the field. We omit the key entirely when req.email is missing to keep metadata minimal. 2. When an existing Customer subscribes again with a changed email, the gateway only updated the local row; the upstream Stripe Customer stayed pinned to the old address, so card-flow Checkout kept pre-filling the stale email. Add a non-fatal call to adapter.update_customer_email so the change propagates. Failure downgrades to a warn log and the local row still wins, so the next subscribe will retry the sync. Adds an optional update_customer_email to SubscriptionProviderMixin (default raises NotImplementedError) and a Stripe.Customer.modify-based implementation in StripeAdapter. Five regression tests cover the metadata propagation and the three sync paths (changed / unchanged / provider-failure).
Follow-up review of the previous email-prefill commit found four issues all related to how req.email and customer.email flow into Stripe Checkout. 1. _get_or_create_customer's failure path was self-contradicting: the comment promised "next subscribe will retry", but customer.email was reassigned outside the try block, so a transient provider failure would freeze the local row on the new email and make every subsequent call short-circuit the diff check. Move the local assignment into the success path; only the explicit NotImplementedError branch (provider can never sync) advances the local row, so retry actually retries. 2. RenewalService skipped the same prefill step entirely. App-managed subscriptions go through _create_renewal_for_subscription / _send_reminder_for_subscription, both of which call adapter.create_payment without forwarding customer.email — so first subscribe got a pre-filled email but every renewal Checkout was blank. Fetch the Customer row once per call and inject customer_email into the renewal metadata. 3. StripeAdapter.create_payment was copying the entire metadata dict (now including the new customer_email key) into the Stripe Session's metadata field and into payment_intent_data.metadata. Stripe's own guidance is to keep PII out of metadata; the customer_email belongs only in the dedicated session_data["customer_email"] prefill field. Strip the key before composing session_metadata. 4. NotImplementedError from update_customer_email was silently passed, making future provider additions invisible. Demote to a structured info log with provider + customer_id so it shows up in observability. Test changes: - Rewrite test_existing_customer_provider_sync_failure_keeps_old_email to assert the local email stays on the old value (the previous assertion locked the buggy "always advance" behavior into the spec). - Add test_existing_customer_not_implemented_advances_local_email to cover the explicit NotImplementedError fast-path. - Add test_stripe_create_payment_keeps_customer_email_out_of_metadata for the PII isolation contract. - Add test_renewal_payment_forwards_customer_email_for_prefill to lock in the renewal-side prefill. Verified end-to-end against the local container: alipay subscribe still returns customer_email on the Stripe Session and metadata no longer leaks the email field.
…essions Expand wechat_pay supported currencies to match Stripe's full list. When currency is not CNY, set adaptive_pricing.enabled=true so Stripe shows local currency on Checkout. Log currency_conversion events from webhooks for reconciliation auditing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…for adaptive pricing check Replace hardcoded string tuple with existing constant and raw string comparison with Currency enum to improve type safety and maintainability. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…orted Stripe test mode only accepts CNY/HKD for wechat_pay sessions. When the caller-supplied currency is rejected with a currency-related InvalidRequestError, retry the session creation with HKD (and drop adaptive_pricing, which is incompatible with the manual currency switch).
…ok forwarding Extend payment gateway to support the ops platform's campaign system: - Add Coupon and PromotionCode SQLAlchemy models with Alembic migration - Add internal CRUD endpoints (/internal/v1/coupons, promotion-codes, plans, subscriptions, refunds) - Extract promotion_code_id from checkout.session.completed events (new + legacy path fallback) - Forward coupon.redeemed and coupon.refunded webhooks to ops-server via WebhookDelivery - Store promotion_code_id in subscription metadata for refund correlation - Add per-App max_delivery_retries override for webhook retry configuration - Pass allow_promotion_codes through to Stripe Checkout session creation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.