feat(payment): add complete payment system with multi-provider support
Add a full payment and subscription system supporting EasyPay (Alipay/WeChat), Stripe, and direct Alipay/WeChat Pay providers with multi-instance load balancing.
This commit is contained in:
@@ -4182,6 +4182,7 @@ export default {
|
||||
email: 'Email',
|
||||
backup: 'Backup',
|
||||
data: 'Sora Storage',
|
||||
payment: 'Payment',
|
||||
},
|
||||
emailTabDisabledTitle: 'Email Verification Not Enabled',
|
||||
emailTabDisabledHint: 'Enable email verification in the Security tab to configure SMTP settings.',
|
||||
@@ -4425,6 +4426,100 @@ export default {
|
||||
moveUp: 'Move Up',
|
||||
moveDown: 'Move Down',
|
||||
},
|
||||
payment: {
|
||||
title: 'Payment Settings',
|
||||
description: 'Configure payment system options',
|
||||
enabled: 'Enable Payment',
|
||||
enabledHint: 'Enable or disable the payment system',
|
||||
enabledPaymentTypes: 'Enabled Providers',
|
||||
enabledPaymentTypesHint: 'Disabling a provider will also disable its instances',
|
||||
minAmount: 'Minimum Amount',
|
||||
maxAmount: 'Maximum Amount',
|
||||
dailyLimit: 'Daily Limit',
|
||||
orderTimeout: 'Order Timeout',
|
||||
orderTimeoutHint: 'In minutes, minimum 1',
|
||||
maxPendingOrders: 'Max Pending Orders',
|
||||
cancelRateLimit: 'Limit Cancel Rate',
|
||||
cancelRateLimitHint: 'When enabled, users who exceed the cancel limit within the time window cannot create new orders',
|
||||
cancelRateLimitEvery: 'Every',
|
||||
cancelRateLimitAllowMax: 'allow max',
|
||||
cancelRateLimitTimes: 'cancels',
|
||||
cancelRateLimitWindow: 'Window',
|
||||
cancelRateLimitUnit: 'Unit',
|
||||
cancelRateLimitMax: 'Max Cancels',
|
||||
cancelRateLimitUnitMinute: 'Minutes',
|
||||
cancelRateLimitUnitHour: 'Hours',
|
||||
cancelRateLimitUnitDay: 'Days',
|
||||
cancelRateLimitWindowMode: 'Window Mode',
|
||||
cancelRateLimitWindowModeRolling: 'Rolling',
|
||||
cancelRateLimitWindowModeFixed: 'Fixed',
|
||||
helpText: 'Help Text',
|
||||
helpImageUrl: 'Help Image URL',
|
||||
manageProviders: 'Manage Providers',
|
||||
balancePaymentDisabled: 'Disable Balance Recharge',
|
||||
noLimit: 'Empty = no limit',
|
||||
helpImage: 'Help Image',
|
||||
helpImagePlaceholder: 'Upload or enter image URL',
|
||||
helpTextPlaceholder: 'Enter help text...',
|
||||
providerEasypay: 'EasyPay',
|
||||
providerAlipay: 'Alipay (Direct)',
|
||||
providerWxpay: 'WeChat Pay (Direct)',
|
||||
providerStripe: 'Stripe',
|
||||
typeDisabled: 'type disabled',
|
||||
enableTypesFirst: 'Enable at least one payment type above first',
|
||||
easypayRedirect: 'Redirect',
|
||||
paymentMode: 'Payment Mode',
|
||||
modeRedirect: 'Redirect',
|
||||
modeQRCode: 'QR Code',
|
||||
modePopup: 'Popup',
|
||||
validationNameRequired: 'Provider name is required',
|
||||
validationTypesRequired: 'Please select at least one supported payment type',
|
||||
validationFieldRequired: '{field} is required',
|
||||
field_apiBase: 'API Base URL',
|
||||
field_notifyUrl: 'Notify URL',
|
||||
field_returnUrl: 'Return URL',
|
||||
callbackBaseUrl: 'Callback Base URL',
|
||||
field_privateKey: 'Private Key',
|
||||
field_publicKey: 'Public Key',
|
||||
field_mchId: 'Merchant ID',
|
||||
field_apiV3Key: 'API v3 Key',
|
||||
field_publicKeyId: 'Public Key ID',
|
||||
field_certSerial: 'Certificate Serial',
|
||||
field_secretKey: 'Secret Key',
|
||||
field_publishableKey: 'Publishable Key',
|
||||
field_webhookSecret: 'Webhook Secret',
|
||||
field_cid: 'Channel ID',
|
||||
field_cidAlipay: 'Alipay Channel ID',
|
||||
field_cidWxpay: 'WeChat Channel ID',
|
||||
stripeWebhookHint: 'Configure the following URL as a Webhook endpoint in Stripe Dashboard:',
|
||||
limitsTitle: 'Limits',
|
||||
limitSingleMin: 'Min per order',
|
||||
limitSingleMax: 'Max per order',
|
||||
limitDaily: 'Daily limit',
|
||||
limitsHint: 'All empty = use global config; partially filled = empty means no limit',
|
||||
limitsUseGlobal: 'Use global',
|
||||
limitsNoLimit: 'No limit',
|
||||
productNamePrefix: 'Product Name Prefix',
|
||||
productNameSuffix: 'Product Name Suffix',
|
||||
preview: 'Preview',
|
||||
loadBalanceStrategy: 'Load Balance Strategy',
|
||||
strategyRoundRobin: 'Round Robin',
|
||||
strategyLeastAmount: 'Least Daily Amount',
|
||||
providerManagement: 'Provider Management',
|
||||
providerManagementDesc: 'Manage payment provider instances',
|
||||
createProvider: 'Add Provider',
|
||||
editProvider: 'Edit Provider',
|
||||
deleteProvider: 'Delete Provider',
|
||||
deleteProviderConfirm: 'Are you sure you want to delete this provider?',
|
||||
providerName: 'Provider Name',
|
||||
providerKey: 'Provider Type',
|
||||
selectProviderKey: 'Select Provider Type',
|
||||
providerConfig: 'Credentials',
|
||||
noProviders: 'No provider instances configured',
|
||||
supportedTypes: 'Supported Payment Types',
|
||||
supportedTypesHint: 'Comma-separated, e.g. alipay,wxpay',
|
||||
refundEnabled: 'Allow Refund',
|
||||
},
|
||||
smtp: {
|
||||
title: 'SMTP Settings',
|
||||
description: 'Configure email sending for verification codes',
|
||||
@@ -5074,4 +5169,260 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
payment: {
|
||||
title: 'Recharge / Subscription',
|
||||
amountLabel: 'Amount',
|
||||
quickAmounts: 'Quick Amounts',
|
||||
customAmount: 'Custom Amount',
|
||||
enterAmount: 'Enter amount',
|
||||
paymentMethod: 'Payment Method',
|
||||
fee: 'Fee',
|
||||
actualPay: 'Actual Payment',
|
||||
createOrder: 'Confirm Payment',
|
||||
methods: {
|
||||
easypay: 'EasyPay',
|
||||
alipay: 'Alipay',
|
||||
wxpay: 'WeChat Pay',
|
||||
stripe: 'Stripe',
|
||||
card: 'Card',
|
||||
link: 'Link',
|
||||
alipay_direct: 'Alipay (Direct)',
|
||||
wxpay_direct: 'WeChat Pay (Direct)',
|
||||
},
|
||||
status: {
|
||||
pending: 'Pending',
|
||||
paid: 'Paid',
|
||||
recharging: 'Recharging',
|
||||
completed: 'Completed',
|
||||
expired: 'Expired',
|
||||
cancelled: 'Cancelled',
|
||||
failed: 'Failed',
|
||||
refund_requested: 'Refund Requested',
|
||||
refunding: 'Refunding',
|
||||
refunded: 'Refunded',
|
||||
partially_refunded: 'Partially Refunded',
|
||||
refund_failed: 'Refund Failed',
|
||||
},
|
||||
qr: {
|
||||
scanToPay: 'Scan to Pay',
|
||||
scanAlipay: 'Alipay QR Payment',
|
||||
scanWxpay: 'WeChat QR Payment',
|
||||
scanAlipayHint: 'Open Alipay on your phone and scan the QR code to pay',
|
||||
scanWxpayHint: 'Open WeChat on your phone and scan the QR code to pay',
|
||||
payInNewWindow: 'Complete Payment in New Window',
|
||||
payInNewWindowHint: 'The payment page has opened in a new window. Please complete the payment there and return to this page.',
|
||||
openPayWindow: 'Reopen Payment Page',
|
||||
expiresIn: 'Expires in',
|
||||
expired: 'Order Expired',
|
||||
expiredDesc: 'This order has expired. Please create a new one.',
|
||||
cancelled: 'Order Cancelled',
|
||||
cancelledDesc: 'You have cancelled this payment.',
|
||||
waitingPayment: 'Waiting for payment...',
|
||||
cancelOrder: 'Cancel Order',
|
||||
},
|
||||
orders: {
|
||||
title: 'My Orders',
|
||||
empty: 'No orders yet',
|
||||
orderId: 'Order ID',
|
||||
orderNo: 'Order No.',
|
||||
amount: 'Amount',
|
||||
payAmount: 'Paid',
|
||||
status: 'Status',
|
||||
paymentMethod: 'Payment Method',
|
||||
createdAt: 'Created',
|
||||
cancel: 'Cancel Order',
|
||||
userId: 'User ID',
|
||||
requestRefund: 'Request Refund',
|
||||
},
|
||||
result: {
|
||||
success: 'Payment Successful',
|
||||
subscriptionSuccess: 'Subscription Successful',
|
||||
failed: 'Payment Failed',
|
||||
backToRecharge: 'Back to Recharge',
|
||||
viewOrders: 'View Orders',
|
||||
},
|
||||
currentBalance: 'Current Balance',
|
||||
rechargeAccount: 'Recharge Account',
|
||||
activeSubscription: 'Active Subscription',
|
||||
noActiveSubscription: 'No active subscription',
|
||||
tabTopUp: 'Top Up',
|
||||
tabSubscribe: 'Subscribe',
|
||||
noPlans: 'No subscription plans available',
|
||||
notAvailable: 'Top-up is currently unavailable',
|
||||
confirmSubscription: 'Confirm Subscription',
|
||||
confirmCancel: 'Are you sure you want to cancel this order?',
|
||||
amountTooLow: 'Minimum amount is {min}',
|
||||
amountTooHigh: 'Maximum amount is {max}',
|
||||
amountNoMethod: 'No payment method available for this amount',
|
||||
refundReason: 'Refund Reason',
|
||||
refundReasonPlaceholder: 'Please describe your refund reason',
|
||||
stripeLoadFailed: 'Failed to load payment component. Please refresh and try again.',
|
||||
stripeMissingParams: 'Missing order ID or client secret',
|
||||
stripeNotConfigured: 'Stripe is not configured',
|
||||
errors: {
|
||||
tooManyPending: 'Too many pending orders (max {max}). Please complete or cancel existing orders first.',
|
||||
cancelRateLimited: 'Too many cancellations. Please try again later.',
|
||||
PENDING_ORDERS: 'This provider has pending orders. Please wait for them to complete before making changes.',
|
||||
},
|
||||
stripePay: 'Pay Now',
|
||||
stripeSuccessProcessing: 'Payment successful, processing your order...',
|
||||
stripePopup: {
|
||||
redirecting: 'Redirecting to payment page...',
|
||||
loadingQr: 'Loading WeChat Pay QR code...',
|
||||
timeout: 'Timed out waiting for payment credentials, please retry',
|
||||
qrFailed: 'Failed to get WeChat Pay QR code',
|
||||
},
|
||||
subscribeNow: 'Subscribe Now',
|
||||
renewNow: 'Renew',
|
||||
selectPlan: 'Select Plan',
|
||||
planFeatures: 'Features',
|
||||
planCard: {
|
||||
rate: 'Rate',
|
||||
dailyLimit: 'Daily',
|
||||
weeklyLimit: 'Weekly',
|
||||
monthlyLimit: 'Monthly',
|
||||
quota: 'Quota',
|
||||
unlimited: 'Unlimited',
|
||||
models: 'Models',
|
||||
},
|
||||
days: 'days',
|
||||
months: 'months',
|
||||
years: 'years',
|
||||
oneMonth: '1 Month',
|
||||
oneYear: '1 Year',
|
||||
perMonth: 'month',
|
||||
perYear: 'year',
|
||||
admin: {
|
||||
tabs: {
|
||||
overview: 'Overview',
|
||||
orders: 'Orders',
|
||||
channels: 'Channels',
|
||||
plans: 'Plans',
|
||||
},
|
||||
todayRevenue: 'Today Revenue',
|
||||
totalRevenue: 'Total Revenue',
|
||||
todayOrders: 'Today Orders',
|
||||
orderCount: 'Order Count',
|
||||
avgAmount: 'Average Amount',
|
||||
revenue: 'Revenue',
|
||||
dailyRevenue: 'Daily Revenue',
|
||||
paymentDistribution: 'Payment Distribution',
|
||||
colUser: 'User',
|
||||
topUsers: 'Top Users',
|
||||
noData: 'No data',
|
||||
days: 'days',
|
||||
weeks: 'weeks',
|
||||
months: 'months',
|
||||
searchOrders: 'Search orders...',
|
||||
allStatuses: 'All Statuses',
|
||||
allPaymentTypes: 'All Payment Types',
|
||||
allOrderTypes: 'All Order Types',
|
||||
orderDetail: 'Order Detail',
|
||||
orderType: 'Order Type',
|
||||
orders: 'Orders',
|
||||
balanceOrder: 'Balance Top-Up',
|
||||
subscriptionOrder: 'Subscription',
|
||||
paidAt: 'Paid At',
|
||||
completedAt: 'Completed At',
|
||||
expiresAt: 'Expires At',
|
||||
feeRate: 'Fee Rate',
|
||||
refund: 'Refund',
|
||||
refundOrder: 'Refund Order',
|
||||
refundAmount: 'Refund Amount',
|
||||
maxRefundable: 'Max Refundable',
|
||||
refundReason: 'Refund Reason',
|
||||
refundReasonPlaceholder: 'Please enter refund reason',
|
||||
confirmRefund: 'Confirm Refund',
|
||||
refundSuccess: 'Refund successful',
|
||||
refundInfo: 'Refund Info',
|
||||
refundEnabled: 'Refund Enabled',
|
||||
alreadyRefunded: 'Already Refunded',
|
||||
deductBalance: 'Deduct Balance',
|
||||
deductBalanceHint: 'Subtract recharged amount from user balance',
|
||||
userBalance: 'User Balance',
|
||||
orderAmount: 'Order Amount',
|
||||
insufficientBalance: 'Insufficient balance — will deduct to $0',
|
||||
noDeduction: 'Will NOT deduct user balance',
|
||||
forceRefund: 'Force refund (ignore balance check)',
|
||||
orderCancelled: 'Order Cancelled',
|
||||
retry: 'Retry',
|
||||
retrySuccess: 'Retry successful',
|
||||
approveRefund: 'Approve Refund',
|
||||
retryRefund: 'Retry Refund',
|
||||
refundRequestInfo: 'Refund Request Info',
|
||||
refundRequestedAt: 'Requested At',
|
||||
refundRequestedBy: 'Requested By',
|
||||
refundRequestReason: 'Request Reason',
|
||||
auditLogs: 'Audit Logs',
|
||||
operator: 'Operator',
|
||||
channelName: 'Channel Name',
|
||||
channelDescription: 'Channel Description',
|
||||
createChannel: 'Create Channel',
|
||||
editChannel: 'Edit Channel',
|
||||
deleteChannel: 'Delete Channel',
|
||||
deleteChannelConfirm: 'Are you sure you want to delete this channel?',
|
||||
planName: 'Plan Name',
|
||||
planDescription: 'Plan Description',
|
||||
createPlan: 'Create Plan',
|
||||
editPlan: 'Edit Plan',
|
||||
deletePlan: 'Delete Plan',
|
||||
deletePlanConfirm: 'Are you sure you want to delete this plan?',
|
||||
originalPrice: 'Original Price',
|
||||
price: 'Price',
|
||||
validityDays: 'Validity (days)',
|
||||
validityUnit: 'Validity Unit',
|
||||
sortOrder: 'Sort Order',
|
||||
forSale: 'For Sale',
|
||||
onSale: 'On Sale',
|
||||
offSale: 'Off Sale',
|
||||
group: 'Group',
|
||||
groupId: 'Group ID',
|
||||
features: 'Features',
|
||||
featuresHint: 'One feature per line',
|
||||
featuresPlaceholder: 'Enter plan features...',
|
||||
providerManagement: 'Provider Management',
|
||||
providerManagementDesc: 'Manage payment provider instances',
|
||||
createProvider: 'Create Provider',
|
||||
editProvider: 'Edit Provider',
|
||||
deleteProvider: 'Delete Provider',
|
||||
deleteProviderConfirm: 'Are you sure you want to delete this provider?',
|
||||
providerName: 'Provider Name',
|
||||
providerKey: 'Provider Key',
|
||||
selectProviderKey: 'Select Provider Key',
|
||||
providerConfig: 'Provider Config',
|
||||
noProviders: 'No providers configured',
|
||||
noProvidersHint: 'Create a provider instance to start accepting payments',
|
||||
supportedTypes: 'Supported Payment Types',
|
||||
supportedTypesHint: 'Select the payment types this provider supports',
|
||||
rateMultiplier: 'Rate Multiplier',
|
||||
dashboardTitle: 'Payment Dashboard',
|
||||
dashboardDesc: 'Recharge order analytics and insights',
|
||||
daySuffix: 'd',
|
||||
paymentConfigTitle: 'Payment Config',
|
||||
paymentConfigDesc: 'Configure payment providers and settings',
|
||||
plansPageTitle: 'Subscription Plans',
|
||||
plansPageDesc: 'Manage subscription plan configuration',
|
||||
tabPlanConfig: 'Plan Configuration',
|
||||
tabUserSubs: 'User Subscriptions',
|
||||
selectGroup: 'Select a group',
|
||||
groupMissing: 'Missing',
|
||||
groupInfo: 'Group Info',
|
||||
platform: 'Platform',
|
||||
rateMultiplierLabel: 'Rate',
|
||||
dailyLimit: 'Daily Limit',
|
||||
weeklyLimit: 'Weekly Limit',
|
||||
monthlyLimit: 'Monthly Limit',
|
||||
unlimited: 'Unlimited',
|
||||
searchUserSubs: 'Search user subscriptions...',
|
||||
daily: 'D',
|
||||
weekly: 'W',
|
||||
monthly: 'M',
|
||||
subsStatus: {
|
||||
active: 'Active',
|
||||
expired: 'Expired',
|
||||
revoked: 'Revoked',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user