Commit Graph
3510 Commits
Author SHA1 Message Date
erio 72b77306da fix(admin): reload provider list after save to get correct data format
UpdateProvider API returns raw DB entity (encrypted config, string types),
but frontend needs ProviderInstanceResponse (decrypted, array types).
Reload full list after save to ensure correct data and sort order.
2026-04-10 01:28:54 +08:00
erio e45c774ab9 fix(payment): refresh provider registry on config changes
- Call RefreshProviders after Create/Update/Delete provider instance
- Call RefreshProviders after saving payment settings
- Auto-save settings when provider dialog saves
- Fixes webhook signature verification using stale pkey
2026-04-10 00:50:12 +08:00
erio 087cd72371 style(admin): widen time unit select, shorten cancel limit label 2026-04-10 00:19:32 +08:00
erio 7617ed56d3 style(admin): cancel rate limit inline with toggle, greyed when off 2026-04-10 00:13:16 +08:00
erio 83643f2dde style(admin): cancel rate limit as toggle switch, config in single row 2026-04-10 00:03:54 +08:00
erio a6728b9b69 style(admin): move cancel rate limit checkbox inline with pending orders row 2026-04-09 23:58:52 +08:00
erio 62e9453ddc refactor(frontend): extract shared OrderTable component
- Create OrderTable.vue with shared cell rendering (ID, order number,
  amount, payment method, status badge, created time)
- Accepts showUser prop to conditionally show user_email column
- Actions column uses scoped slot for view-specific buttons
- UserOrdersView and AdminOrdersView both use OrderTable
- Removes duplicated DataTable cell templates from both views

chore: bump version to 0.1.108.144
2026-04-09 23:49:47 +08:00
erio 753a87dee3 feat(admin): add user info and keyword search to admin order list
Backend:
- Add Keyword field to OrderListParams
- AdminListOrders supports keyword search on out_trade_no, user_email, user_name
- PaymentOrder already has user_email/user_name/user_notes fields (no join needed)

Frontend:
- Replace inline status badge with OrderStatusBadge component
- Replace user_id column with user_email (shows email, fallback to username, with notes)
- Keyword search matches order number and user info

chore: bump version to 0.1.108.143
2026-04-09 23:41:59 +08:00
erio e9aa1b1330 fix(payment): use order's original provider instance for refund
Previously gwRefund used registry.GetProvider(paymentType) which returns
an arbitrary instance for that type. When multiple instances share the
same payment type (e.g., two EasyPay merchants both supporting alipay),
the refund would be sent to the wrong merchant.

Now getRefundProvider() reads the order's ProviderInstanceID, loads that
instance's config, and creates the correct provider. Falls back to
registry lookup for legacy orders without an instance ID.

chore: bump version to 0.1.108.142
2026-04-09 23:21:38 +08:00
erio 69f885eb5f style: fix gofmt formatting in payment_handler.go 2026-04-09 22:52:11 +08:00
erio fdc9835c52 fix(ci): update Go version check to 1.26.2 in CI workflows 2026-04-09 22:43:14 +08:00
erio 63c4172dd9 fix(ci): upgrade Go to 1.26.2 for security fixes, fix flaky WS test
- Upgrade Go from 1.26.1 to 1.26.2 in go.mod and Dockerfile to fix
  govulncheck findings (GO-2026-4947, GO-2026-4946, GO-2026-4870, etc.)
- Fix flaky PassthroughModeRelaysByCaddyAdapter test: tolerate
  StatusNormalClosure error from server after client closes connection
2026-04-09 22:38:39 +08:00
erio e25e7b3f2d fix(admin): fix refund dialog amount for REFUND_REQUESTED, improve button styles
- Don't treat refund_amount as "already refunded" in REFUND_REQUESTED status
  (it's the requested amount, not actually refunded)
- Pre-fill refund amount with user's requested amount
- Show "already refunded" only for PARTIALLY_REFUNDED/REFUNDED orders
- Change action buttons from stacked icon+text to compact inline style
2026-04-09 22:07:06 +08:00
erio 66cd16fce3 fix: remove unused canRefund, fix TS type assertions 2026-04-09 21:49:05 +08:00
erio cc858c3cc9 feat(admin): enhance refund workflow to match sub2apipay
Admin order list:
- Add REFUND_REQUESTED "approve refund" button with amount badge
- Add REFUND_FAILED "retry refund" button
- Add missing status filters (REFUND_REQUESTED, REFUND_FAILED)
- Order detail dialog: show refund request info + audit logs

Admin refund dialog:
- Show refund request info card (violet) when user requested
- Display user balance with insufficient balance warning
- Add "no deduction" info when deduct_balance unchecked
- Add force refund checkbox (shown when requireForce=true)
- Add warning display prop
- Pre-fill reason from user's refund request
- Default deduct_balance to true

chore: bump version to 0.1.108.141
2026-04-09 21:47:39 +08:00
erio ceee2d0584 fix: audit fixes - magic strings to constants, frontend any/catch, LB tests
Backend:
- Define OrderTypeBalance/Subscription, EntityStatusActive, DeductionType*,
  NotificationStatus* constants in payment/types.go
- Replace all magic strings in payment_order, payment_fulfillment, payment_refund
- Add local constants in easypay.go (tradeStatusSuccess, signTypeMD5)
- Add 27 unit tests for load balancer (filterByLimits, pickLeastAmount,
  getInstanceChannelLimits, startOfDay)

Frontend:
- Remove all `any` types in SettingsView.vue (18 catch blocks + 1 payload)
- Fix bare catch blocks in PaymentResultView, PaymentView
- Add `unknown` type annotation to all catch blocks

chore: bump version to 0.1.108.140
2026-04-09 21:29:49 +08:00
erio 44a9d91c8f refactor(payment): rewrite load balancer with complete limit checking
- Batch-query daily usage in one SQL (GroupBy) instead of N queries
- Include PENDING orders in daily usage to prevent over-committing
- Check remaining capacity (used + orderAmount > limit) not just used >= limit
- Check SingleMin/SingleMax per-channel limits
- Pre-attach usage to candidates, reuse across filter and strategy pick
- Fallback to full list with warn log when all instances exhausted

chore: bump version to 0.1.108.139
2026-04-09 21:20:13 +08:00
erio 8808910ee7 fix(frontend): unify currency to $ and add order number to admin orders
- Replace all ¥ / ¥ with $ across all payment views and components
- Add out_trade_no column to admin order list table
- Add order number field to admin order detail dialog

chore: bump version to 0.1.108.138
2026-04-09 21:14:57 +08:00
erio e5dd87743f fix(payment): filter instances by remaining capacity and single amount range
Check used + orderAmount > dailyLimit (not just used >= limit) and
also filter by SingleMin/SingleMax per-channel limits.

chore: bump version to 0.1.108.137
2026-04-09 19:33:36 +08:00
erio fc99a88fee fix(payment): implement least-amount load balance strategy
Previously SelectInstance always used round-robin regardless of the
configured strategy. Now it reads the strategy from payment config
and selects the instance with the lowest daily transaction amount
when "least-amount" is configured.

chore: bump version to 0.1.108.136
2026-04-09 19:20:20 +08:00
erio b25d7f3179 fix(frontend): restore RechargeSubscriptionIcon for purchase menu
chore: bump version to 0.1.108.135
2026-04-09 19:01:34 +08:00
erio 766f9fc590 fix: cast platform to string to fix TS2345 2026-04-09 18:48:42 +08:00
erio 05ce6d6bc0 feat(admin): add platform colors to plan edit group selector
chore: bump version to 0.1.108.134
2026-04-09 18:46:58 +08:00
erio acb86102f4 feat(admin): color plan names by group platform
chore: bump version to 0.1.108.133
2026-04-09 18:33:36 +08:00
erio 0c00a883a3 chore: bump version to 0.1.108.132 2026-04-09 18:19:32 +08:00
erio 4bacf47e45 fix(admin): only show subscription-type groups in plan group selector 2026-04-09 18:19:31 +08:00
erio 3d547d85cb chore: bump version to 0.1.108.131 2026-04-09 18:04:04 +08:00
erio 3ce57cade8 fix(payment): use Stripe built-in QR dialog for WeChat Pay
Remove handleActions:false and custom QR rendering. Let Stripe's
native QR dialog handle WeChat Pay display in the popup window.
2026-04-09 18:04:04 +08:00
erio 5c17718633 chore: bump version to 0.1.108.130 2026-04-09 17:49:09 +08:00
erio ae1709a616 fix(payment): use normal style for order number column 2026-04-09 17:49:09 +08:00
erio aa1b87fdbb chore: bump version to 0.1.108.129 2026-04-09 17:43:42 +08:00
erio 3098651bdd fix(payment): show order number as separate column in order list 2026-04-09 17:43:42 +08:00
erio 8c73ded205 chore: bump version to 0.1.108.128 2026-04-09 17:34:23 +08:00
erio 49a36e55a9 feat(payment): show out_trade_no in order list 2026-04-09 17:34:23 +08:00
erio 2f6d926a9b chore: bump version to 0.1.108.127 2026-04-09 17:29:18 +08:00
erio cb9dcaec2e fix(payment): show both order ID and order number in result pages
Display order ID (#24) and order number (sub2_xxx) as separate rows
in payment result and status panel success views.
2026-04-09 17:29:18 +08:00
erio e42838eb82 chore: bump version to 0.1.108.126 2026-04-09 17:23:23 +08:00
erio 01864a7a1e fix(payment): ensure providers loaded before webhook, show out_trade_no
- Call EnsureProviders before webhook provider lookup to fix
  "provider not registered" error after restart or config changes
- Display out_trade_no instead of numeric ID in payment result pages
2026-04-09 17:23:23 +08:00
erio 3f557d0f9d chore: bump version to 0.1.108.125 2026-04-09 17:14:39 +08:00
erio cfc20f6670 fix(admin): preserve provider list order after editing
Update provider in place instead of reloading the entire list,
which could change the display order.
2026-04-09 17:14:39 +08:00
erio 8e4641e176 chore: bump version to 0.1.108.124 2026-04-09 16:39:22 +08:00
erio 5ae2061d05 fix(admin): fix payment provider settings issues
- Remove "at least one payment type required" validation, allow
  saving providers with no payment types selected
- Auto-fill current domain for empty notify/return URL on save
  (trim whitespace, fall back to window.location.origin)
- Add type="button" to all buttons inside the settings form that
  are not submit buttons (edit, delete, refresh, create provider)
  to prevent accidental form submission triggering main settings save
2026-04-09 16:39:22 +08:00
erio 9fdc7c92e2 chore: bump version to 0.1.108.123 2026-04-09 16:07:26 +08:00
erio 11ba3b6ecd fix(payment): restore Stripe popup flow, fix WeChat double QR dialog
Restore popup handling for Stripe Alipay/WeChat (reverts inline-only change).
Fix WeChat double QR issue by passing handleActions: false to
confirmWechatPayPayment, which prevents Stripe's built-in QR dialog
and lets our popup render the QR code directly.

Flow after fix:
- Stripe Alipay: popup → redirects to Alipay
- Stripe WeChat: popup → directly shows QR code (no Stripe dialog)
- Stripe Card: inline confirm → success page
2026-04-09 16:07:26 +08:00
erio 1ffea8faec chore: bump version to 0.1.108.122 2026-04-09 15:41:24 +08:00
erio 8b4e6bf317 refactor(payment): unify Stripe payment flow, remove StripePopupView dependency
All Stripe methods now use confirmPayment({redirect: 'if_required'}):
- Card: confirms inline, shows success page
- WeChat: Stripe shows QR modal overlay on same page, no popup
- Alipay: Stripe redirects to Alipay page, returns to result page

Removes POPUP_METHODS, StripePopupView postMessage handshake, and
onStripeRedirect handler. Eliminates double-popup issue for WeChat
(3 windows → 1) and simplifies Alipay (2 windows → 1 redirect).
2026-04-09 15:41:07 +08:00
erio 7505c745d2 chore: bump version to 0.1.108.121 2026-04-09 15:21:44 +08:00
erio 8a98f726b9 fix(payment): show success screen after Stripe card payment instead of auto-returning
Stripe card payment now shows a success page with order details and a
manual confirm button, matching the QR code payment success flow.
Previously it auto-returned to the recharge page after 1.5 seconds.
2026-04-09 15:21:23 +08:00
erio 5c94b51d04 chore: bump version to 0.1.108.120 2026-04-09 14:56:38 +08:00
erio 03b97f14ad fix(payment): add return_url verification for popup payment mode
EasyPay popup mode relies on notify_url (webhook) to update order status,
but if the callback is missed, orders stay PENDING forever. This adds:

- POST /api/v1/payment/orders/verify endpoint that actively queries
  the upstream provider to check payment status
- Frontend PaymentResultView calls verify when receiving EasyPay
  return_url params (out_trade_no)
- Fix checkPaid to fall back to OutTradeNo when PaymentTradeNo is empty
  (popup mode doesn't have trade_no until the notify callback)
2026-04-09 14:56:24 +08:00