This commit is contained in:
18631081161 2025-12-24 16:26:43 +08:00
parent c79e164f87
commit 1b0cc39255
7 changed files with 60 additions and 33 deletions

View File

@ -595,7 +595,9 @@ function formatPaymentDetails(method, details) {
case 'alipay':
return parsed.alipayAccount || parsed.account || '-'
case 'bank':
return parsed.bankAccount ? `****${parsed.bankAccount.slice(-4)}` : '-'
// : bankCardNumber () bankAccount ()
const bankAccountNum = parsed.bankCardNumber || parsed.bankAccount
return bankAccountNum ? `****${bankAccountNum.slice(-4)}` : '-'
default:
return '-'
}
@ -614,10 +616,16 @@ function formatPaymentDetailsLong(method, details) {
case 'alipay':
return `支付宝账号: ${parsed.alipayAccount || parsed.account || '-'}`
case 'bank':
// : 使 bankCardNumber/cardholderName, 使 bankAccount/accountName
const bankName = parsed.bankName || '银行'
const account = parsed.bankAccount || '-'
const name = parsed.accountName || '-'
return `${bankName} | 账号: ${account} | 户名: ${name}`
const account = parsed.bankCardNumber || parsed.bankAccount || '-'
const name = parsed.cardholderName || parsed.accountName || '-'
const swiftCode = parsed.swiftCode
let result = `${bankName} | 账号: ${account} | 户名: ${name}`
if (swiftCode) {
result += ` | SWIFT: ${swiftCode}`
}
return result
default:
return JSON.stringify(parsed)
}

View File

@ -126,7 +126,7 @@ const approveWithdrawal = async (withdrawalId, adminId, notes = '') => {
{
model: User,
as: 'user',
attributes: ['id', 'balance'],
attributes: ['id', 'balance', 'balancePeso'],
},
],
});
@ -140,31 +140,7 @@ const approveWithdrawal = async (withdrawalId, adminId, notes = '') => {
throw new Error(`Cannot approve withdrawal with status: ${withdrawal.status}`);
}
// Get user with lock
const user = await User.findByPk(withdrawal.userId, {
transaction,
lock: transaction.LOCK.UPDATE,
});
if (!user) {
throw new Error('User not found');
}
// Check if user has sufficient balance
const withdrawalAmount = parseFloat(withdrawal.amount);
const userBalance = parseFloat(user.balance);
if (userBalance < withdrawalAmount) {
throw new Error('User has insufficient balance');
}
// Update user balance
const newBalance = userBalance - withdrawalAmount;
await user.update({
balance: newBalance,
}, { transaction });
// Update withdrawal status
// Update withdrawal status (balance was already deducted when user submitted the request)
await withdrawal.update({
status: 'completed',
reviewedBy: adminId,
@ -176,15 +152,23 @@ const approveWithdrawal = async (withdrawalId, adminId, notes = '') => {
logger.info(`Withdrawal ${withdrawal.withdrawalNo} approved by admin ${adminId}`);
// Get current user balance for response
const user = withdrawal.user;
const currency = withdrawal.currency || 'CNY';
const currentBalance = currency === 'PHP'
? parseFloat(user?.balancePeso || 0).toFixed(2)
: parseFloat(user?.balance || 0).toFixed(2);
return {
id: withdrawal.id,
withdrawalNo: withdrawal.withdrawalNo,
amount: parseFloat(withdrawal.amount).toFixed(2),
currency: currency,
status: withdrawal.status,
reviewedBy: withdrawal.reviewedBy,
reviewedAt: withdrawal.reviewedAt,
completedAt: withdrawal.completedAt,
userBalance: newBalance.toFixed(2),
userBalance: currentBalance,
};
} catch (error) {
await transaction.rollback();
@ -223,6 +207,27 @@ const rejectWithdrawal = async (withdrawalId, adminId, reason) => {
throw new Error(`Cannot reject withdrawal with status: ${withdrawal.status}`);
}
// Get user with lock to refund the balance
const user = await User.findByPk(withdrawal.userId, {
transaction,
lock: transaction.LOCK.UPDATE,
});
if (!user) {
throw new Error('User not found');
}
// Refund the withdrawal amount to user balance based on currency
const withdrawalAmount = parseFloat(withdrawal.amount);
const currency = withdrawal.currency || 'CNY';
if (currency === 'PHP') {
user.balancePeso = parseFloat(user.balancePeso || 0) + withdrawalAmount;
} else {
user.balance = parseFloat(user.balance || 0) + withdrawalAmount;
}
await user.save({ transaction });
// Update withdrawal status
await withdrawal.update({
status: 'rejected',
@ -233,12 +238,13 @@ const rejectWithdrawal = async (withdrawalId, adminId, reason) => {
await transaction.commit();
logger.info(`Withdrawal ${withdrawal.withdrawalNo} rejected by admin ${adminId}`);
logger.info(`Withdrawal ${withdrawal.withdrawalNo} rejected by admin ${adminId}, amount refunded to user`);
return {
id: withdrawal.id,
withdrawalNo: withdrawal.withdrawalNo,
amount: parseFloat(withdrawal.amount).toFixed(2),
currency: currency,
status: withdrawal.status,
reviewedBy: withdrawal.reviewedBy,
reviewedAt: withdrawal.reviewedAt,

View File

@ -108,6 +108,16 @@ const createWithdrawal = async (userId, withdrawalData) => {
status: 'waiting',
}, { transaction });
// Deduct amount from user balance based on currency
if (currency === 'PHP') {
user.balancePeso = parseFloat(user.balancePeso || 0) - withdrawalAmount;
if (user.balancePeso < 0) user.balancePeso = 0;
} else {
user.balance = parseFloat(user.balance || 0) - withdrawalAmount;
if (user.balance < 0) user.balance = 0;
}
await user.save({ transaction });
await transaction.commit();
return withdrawal;

View File

@ -207,6 +207,7 @@ If you have privacy questions, please contact us through the application.`
enterAmount: 'Please enter withdraw amount',
enterPlaceholder: 'Please enter',
amountHint: 'Minimum 1 yuan per time',
availableWithdraw: 'Available',
nextStep: 'Next Step',
selectPaymentMethod: 'Please select payment method',
wechat: 'WeChat',

View File

@ -207,6 +207,7 @@ Si tiene preguntas sobre privacidad, contáctenos a través de la aplicación.`
enterAmount: 'Por favor, ingrese el monto del retiro',
enterPlaceholder: 'Por favor, ingrese',
amountHint: 'Mínimo 1 yuan por vez',
availableWithdraw: 'Disponible',
nextStep: 'Siguiente Paso',
selectPaymentMethod: 'Por favor, seleccione el método de pago',
wechat: 'WeChat',

View File

@ -223,6 +223,7 @@ export default {
enterAmount: '请输入提现金额',
enterPlaceholder: '请输入',
amountHint: '每次最低1元',
availableWithdraw: '可提现',
nextStep: '下一步',
selectPaymentMethod: '请选择收款方式',
wechat: '微信',

View File

@ -235,7 +235,7 @@
:placeholder="$t('invite.enterPlaceholder')" />
<text class="currency-text">{{ withdrawCurrency === 'CNY' ? '¥' : '₱' }}</text>
</view>
<text class="amount-hint">{{ $t('invite.amountHint') }}{{ withdrawCurrency === 'PHP' ? '₱' : '¥' }}{{ currentAvailableBalance }}</text>
<text class="amount-hint">{{ $t('invite.amountHint') }}{{ $t('invite.availableWithdraw') || '可提现' }}{{ withdrawCurrency === 'PHP' ? '₱' : '¥' }}{{ currentAvailableBalance }}</text>
<view class="apply-btn" @click="nextStep">
<text class="apply-btn-text">{{ $t('invite.nextStep') }}</text>