1. 20 Apr, 2026 1 commit
    • erio's avatar
      feat(payment): i18n payment error codes and label localization · 40d4e167
      erio authored
      Pairs with the backend structured payment errors (reason + metadata). The
      frontend now maps reason codes to localized messages with metadata as
      interpolation variables, and automatically localizes raw config-field names
      (e.g. "certSerial" → "证书序列号") using the existing UI-label i18n
      namespace.
      
      - frontend/src/utils/apiError.ts
        - extractApiErrorCode now prefers the string `reason` over the numeric HTTP
          `code`; reason is granular enough to drive i18n lookup, HTTP code is not.
        - New extractApiErrorMetadata to pull interpolation params off the error.
        - New extractI18nErrorMessage(err, t, namespace, fallback): looks up
          `<namespace>.<REASON>` in i18n and substitutes metadata. Before
          substitution, `metadata.key` and `metadata.keys` (slash-joined) are
          re-translated through `admin.settings.payment.field_<key>` so users see
          "缺少必填项:证书序列号" instead of "缺少必填项:certSerial".
      
      - frontend/src/i18n/locales/{zh,en}.ts
        - Add payment.errors entries for every structured reason code returned by
          the backend (PAYMENT_DISABLED, INVALID_AMOUNT, TOO_MANY_PENDING,
          DAILY_LIMIT_EXCEEDED, NO_AVAILABLE_INSTANCE, PAYMENT_PROVIDER_MISCONFIGURED,
          WXPAY_CONFIG_MISSING_KEY / INVALID_KEY_LENGTH / INVALID_KEY, NOT_FOUND,
          FORBIDDEN, CONFLICT, INVALID_ORDER_TYPE, INVALID_STATUS,
          BALANCE_NOT_ENOUGH, REFUND_AMOUNT_EXCEEDED, REFUND_FAILED, and more),
          with placeholders for template variables.
      
      - 13 payment-related Vue files
        - Migrate catch-block error reporting from extractApiErrorMessage to
          extractI18nErrorMessage(err, t, 'payment.errors', fallback).
        - Remove the ad-hoc paymentErrorMap computed in SettingsView.vue, which the
          new helper supersedes (it reads i18n directly via t).
      
      - frontend/src/components/payment/providerConfig.ts
        - wxpay: publicKey and publicKeyId are now required (was optional), matching
          the pubkey-only verifier direction; certSerial is already required.
      
      This PR is drop-in safe: reason-preferring extractApiErrorCode is backward
      compatible with callers that pass their own i18nMap, and error codes missing
      from i18n fall back to the existing message-based path.
      40d4e167
  2. 14 Apr, 2026 1 commit
    • erio's avatar
      fix(payment): audit fixes for alipay/wxpay/stripe payment providers · 5bae3b05
      erio authored
      Backend:
      - Extract YuanToFen/FenToYuan to payment/amount.go using shopspring/decimal
      - Require alipay publicKey in config validation
      - Fix wxpay webhook response to return JSON per V3 spec
      - Remove wxpay certSerial fallback to publicKeyId
      - Define magic strings as named constants in wxpay/alipay providers
      - Add slog warning for wxpay H5→Native payment downgrade
      - Make EncryptionKey validation return error on invalid (non-empty) key
      - Make decryptConfig propagate errors instead of returning nil
      - Add idempotency check in doBalance to prevent stuck FAILED retries
      
      Frontend:
      - Fix dashboard currency symbol from $ to ¥
      - Fix AdminPaymentPlansView any type to proper SubscriptionPlan type
      - Make quick amount buttons follow selected payment method limits
      - Center help image with larger height and text below
      5bae3b05
  3. 11 Apr, 2026 1 commit