1.优化提现接口/api/finance/withdrawCreate
This commit is contained in:
@@ -25,7 +25,7 @@ class WithdrawOrder extends Backend
|
||||
|
||||
protected bool $modelSceneValidate = true;
|
||||
|
||||
protected string|array $quickSearchField = ['id', 'order_no', 'idempotency_key', 'receive_type', 'receive_account', 'remark'];
|
||||
protected string|array $quickSearchField = ['id', 'order_no', 'idempotency_key', 'pay_channel', 'receive_type', 'receive_account', 'ddpay_receiver_name', 'receiver_email', 'receiver_mobile', 'remark'];
|
||||
|
||||
protected string|array $defaultSortField = ['id' => 'desc'];
|
||||
|
||||
@@ -264,9 +264,13 @@ class WithdrawOrder extends Backend
|
||||
} else {
|
||||
$orderNo = is_string($fresh['order_no'] ?? null) ? trim($fresh['order_no'] ?? '') : strval($fresh['order_no'] ?? '');
|
||||
$receiveType = is_string($fresh['receive_type'] ?? null) ? strtolower(trim($fresh['receive_type'] ?? '')) : '';
|
||||
$payChannel = is_string($fresh['pay_channel'] ?? null) ? strtolower(trim($fresh['pay_channel'] ?? '')) : '';
|
||||
if ($payChannel === '') {
|
||||
$payChannel = 'ddpay';
|
||||
}
|
||||
|
||||
// 当前仅接入 bank 类型出金(与移动端 withdrawCreate 校验一致)
|
||||
if ($orderNo !== '' && $receiveType === 'bank') {
|
||||
// 当前仅 ddpay + bank 类型自动出金(与移动端 withdrawCreate 校验一致)
|
||||
if ($orderNo !== '' && $receiveType === 'bank' && $payChannel === 'ddpay') {
|
||||
$base = \app\common\library\finance\DDPayGateway::publicBaseUrlForCallbacks($request);
|
||||
if ($base === '') {
|
||||
$base = 'https://' . strval($request->host());
|
||||
|
||||
@@ -826,18 +826,38 @@ class Finance extends MobileBase
|
||||
}
|
||||
$withdrawCoinRaw = $request->post('withdraw_coin', '');
|
||||
$withdrawCoin = is_string($withdrawCoinRaw) ? trim($withdrawCoinRaw) : (is_numeric($withdrawCoinRaw) ? strval($withdrawCoinRaw) : '');
|
||||
$channelCode = strtolower($this->stringParam($request->post('channel_code')));
|
||||
if ($channelCode === '') {
|
||||
$channelCode = strtolower($this->stringParam($request->post('pay_channel')));
|
||||
}
|
||||
$receiveAccount = trim(is_string($request->post('receive_account', '')) ? $request->post('receive_account', '') : '');
|
||||
$receiveType = trim(is_string($request->post('receive_type', '')) ? $request->post('receive_type', '') : '');
|
||||
$receiveType = strtolower($receiveType);
|
||||
|
||||
// DDPAY 出金(Payout)所需扩展字段:当前仅支持 receive_type=bank
|
||||
$receiverName = trim(is_string($request->post('receiver_name', '')) ? $request->post('receiver_name', '') : '');
|
||||
$receiverEmail = trim(is_string($request->post('receiver_email', '')) ? $request->post('receiver_email', '') : '');
|
||||
$receiverMobile = trim(is_string($request->post('receiver_mobile', '')) ? $request->post('receiver_mobile', '') : '');
|
||||
$bankCode = trim(is_string($request->post('bank_code', '')) ? $request->post('bank_code', '') : '');
|
||||
$bankBranch = trim(is_string($request->post('bank_branch', '')) ? $request->post('bank_branch', '') : '');
|
||||
$idempotencyKey = trim(is_string($request->post('idempotency_key', '')) ? $request->post('idempotency_key', '') : '');
|
||||
if ($withdrawCoin === '' || $receiveAccount === '' || $receiveType === '' || $idempotencyKey === '') {
|
||||
if ($withdrawCoin === '' || $channelCode === '' || $receiveAccount === '' || $receiveType === '' || $idempotencyKey === ''
|
||||
|| $receiverEmail === '' || $receiverMobile === '') {
|
||||
return $this->mobileError(1001, 'Missing parameters');
|
||||
}
|
||||
if (!in_array($channelCode, DepositChannelLib::withdrawPayoutChannelCodes(), true)) {
|
||||
return $this->mobileError(2004, 'Withdraw only supports DDPay');
|
||||
}
|
||||
$effectiveChannels = $this->loadDepositChannelEffective();
|
||||
if (!DepositChannelLib::assertChannelEnabled($channelCode, $effectiveChannels)) {
|
||||
return $this->mobileError(2004, 'Pay channel not available');
|
||||
}
|
||||
if (mb_strlen($receiverEmail) > 255 || !filter_var($receiverEmail, FILTER_VALIDATE_EMAIL)) {
|
||||
return $this->mobileError(1001, 'Invalid receiver email');
|
||||
}
|
||||
if (mb_strlen($receiverMobile) > 64 || !$this->isValidReceiverMobile($receiverMobile)) {
|
||||
return $this->mobileError(1001, 'Invalid receiver mobile');
|
||||
}
|
||||
if (mb_strlen($idempotencyKey) > 64) {
|
||||
return $this->mobileError(1002, 'Idempotency key is too long');
|
||||
}
|
||||
@@ -970,11 +990,14 @@ class Finance extends MobileBase
|
||||
'idempotency_key' => $idempotencyKey,
|
||||
'user_id' => $userId,
|
||||
'channel_id' => $channelId,
|
||||
'pay_channel' => $channelCode,
|
||||
'amount' => $withdrawCoin,
|
||||
'fee' => $feeCoin,
|
||||
'actual_amount' => $actualArrivalCoin,
|
||||
'receive_type' => $receiveType,
|
||||
'receive_account' => $receiveAccount,
|
||||
'receiver_email' => $receiverEmail,
|
||||
'receiver_mobile' => $receiverMobile,
|
||||
'ddpay_receiver_name' => $receiverName,
|
||||
'ddpay_bank_name' => $ddpayBankName,
|
||||
'ddpay_bank_branch' => $bankBranch,
|
||||
@@ -1044,6 +1067,9 @@ class Finance extends MobileBase
|
||||
'actual_arrival_coin' => $this->amountNumber($order->actual_amount ?? '0'),
|
||||
'receive_type' => is_string($order->receive_type ?? null) ? $order->receive_type : strval($order->receive_type ?? ''),
|
||||
'receive_account' => is_string($order->receive_account ?? null) ? $order->receive_account : strval($order->receive_account ?? ''),
|
||||
'pay_channel' => is_string($order->pay_channel ?? null) ? $order->pay_channel : strval($order->pay_channel ?? ''),
|
||||
'receiver_email' => is_string($order->receiver_email ?? null) ? $order->receiver_email : strval($order->receiver_email ?? ''),
|
||||
'receiver_mobile' => is_string($order->receiver_mobile ?? null) ? $order->receiver_mobile : strval($order->receiver_mobile ?? ''),
|
||||
'reject_reason' => $statusCode === 2 && $remark !== '' ? $remark : null,
|
||||
'create_time' => $order->create_time,
|
||||
'review_time' => $order->review_time,
|
||||
@@ -1249,8 +1275,10 @@ class Finance extends MobileBase
|
||||
$wc = $cfg['withdraw_copy'] ?? [];
|
||||
$rateMode = is_array($wc) && isset($wc['rate_mode']) && is_string($wc['rate_mode']) ? $wc['rate_mode'] : 'fixed';
|
||||
|
||||
$payChannels = [];
|
||||
$effectiveCh = DepositChannelLib::effectiveRowsFromDb();
|
||||
$withdrawPayChannels = DepositChannelLib::channelsForWithdraw($effectiveCh, $lang);
|
||||
|
||||
$payChannels = [];
|
||||
$regCh = DepositChannelLib::codeRegistry();
|
||||
foreach ($effectiveCh as $row) {
|
||||
if (!is_array($row)) {
|
||||
@@ -1296,6 +1324,7 @@ class Finance extends MobileBase
|
||||
'banks' => $depositBanks,
|
||||
],
|
||||
'withdraw' => [
|
||||
'pay_channels' => $withdrawPayChannels,
|
||||
'banks' => $withdrawBanks,
|
||||
'min_ewallet' => $minEw,
|
||||
'min_bank' => $minBk,
|
||||
@@ -1312,8 +1341,11 @@ class Finance extends MobileBase
|
||||
// 与 DDPay 出金及 withdrawCreate 一致,不由后台开关配置
|
||||
'fields' => [
|
||||
'receive_type_bank_only' => true,
|
||||
'require_channel_code' => true,
|
||||
'require_receiver_name' => true,
|
||||
'require_receive_account' => true,
|
||||
'require_receiver_email' => true,
|
||||
'require_receiver_mobile' => true,
|
||||
'require_bank_code' => true,
|
||||
'require_bank_branch' => false,
|
||||
],
|
||||
@@ -1365,6 +1397,23 @@ class Finance extends MobileBase
|
||||
return trim($raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 收款人手机号:5–32 位,仅允许数字与常见分隔符(+ - 空格)
|
||||
*/
|
||||
private function isValidReceiverMobile(string $mobile): bool
|
||||
{
|
||||
$len = mb_strlen($mobile);
|
||||
if ($len < 5 || $len > 32) {
|
||||
return false;
|
||||
}
|
||||
if (!preg_match('/^[0-9+\-\s]+$/', $mobile)) {
|
||||
return false;
|
||||
}
|
||||
$digits = preg_replace('/\D/', '', $mobile);
|
||||
|
||||
return is_string($digits) && strlen($digits) >= 5;
|
||||
}
|
||||
|
||||
private function loadEnabledTiers(): array
|
||||
{
|
||||
$row = GameConfig::where('config_key', DepositTierLib::CONFIG_KEY)->find();
|
||||
|
||||
@@ -47,6 +47,8 @@ return [
|
||||
'Deposit tier not available' => 'The selected deposit tier is not available',
|
||||
'Order not found after settle' => 'Order not found after settlement',
|
||||
'Invalid withdraw amount' => 'Invalid withdraw amount',
|
||||
'Invalid receiver email' => 'Invalid receiver email',
|
||||
'Invalid receiver mobile' => 'Invalid receiver mobile',
|
||||
'Withdraw exceeds available bet flow' => 'The withdraw amount exceeds the available bet-flow quota',
|
||||
'Too many pending deposit orders' => 'You already have multiple pending deposit orders, please complete payment first or wait for timeout',
|
||||
'Too many pending withdraw orders' => 'You already have withdraw orders under review, please wait for them to be processed',
|
||||
@@ -58,6 +60,7 @@ return [
|
||||
'Pay channel not available for this currency' => 'The payment channel is not available for this currency',
|
||||
'DDPay deposit initiation failed' => 'DDPay deposit initiation failed',
|
||||
'Deposit only supports DDPay' => 'Only DDPay deposits are supported (channel_code must be ddpay)',
|
||||
'Withdraw only supports DDPay' => 'Only DDPay withdrawals are supported (channel_code must be ddpay)',
|
||||
// Member center account
|
||||
'Data updated successfully~' => 'Data updated successfully~',
|
||||
'Password has been changed~' => 'Password has been changed~',
|
||||
|
||||
@@ -79,6 +79,8 @@ return [
|
||||
'Deposit tier not available' => '所选充值档位不可用',
|
||||
'Order not found after settle' => '充值成功后未找到订单',
|
||||
'Invalid withdraw amount' => '提现金额不合法',
|
||||
'Invalid receiver email' => '收款人邮箱格式不正确',
|
||||
'Invalid receiver mobile' => '收款人手机号格式不正确',
|
||||
'Withdraw exceeds available bet flow' => '提现金额超出可提现额度',
|
||||
'Too many pending deposit orders' => '存在多笔待支付充值订单,请先完成支付或等待超时',
|
||||
'Too many pending withdraw orders' => '用户当前存在多笔提现订单,请等待审核',
|
||||
@@ -90,6 +92,7 @@ return [
|
||||
'Pay channel not available for this currency' => '当前币种不支持该支付渠道',
|
||||
'DDPay deposit initiation failed' => 'DDPay 充值发起失败',
|
||||
'Deposit only supports DDPay' => '仅支持 DDPay 充值(channel_code 须为 ddpay)',
|
||||
'Withdraw only supports DDPay' => '仅支持 DDPay 提现(channel_code 须为 ddpay)',
|
||||
// 会员中心 account
|
||||
'Data updated successfully~' => '资料更新成功~',
|
||||
'Password has been changed~' => '密码已修改~',
|
||||
|
||||
@@ -402,6 +402,72 @@ final class DepositChannel
|
||||
return array_values(array_unique($codes));
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前服务端已对接自动出金的渠道(与 withdrawCreate 校验一致)
|
||||
*
|
||||
* @return list<string>
|
||||
*/
|
||||
public static function withdrawPayoutChannelCodes(): array
|
||||
{
|
||||
return ['ddpay'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<array{code: string, sort: int, status: int, tier_ids: list<string>}> $effectiveRows
|
||||
*/
|
||||
public static function assertChannelEnabled(string $channelCode, array $effectiveRows): bool
|
||||
{
|
||||
$row = self::findMergedByCode($effectiveRows, $channelCode);
|
||||
if ($row === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ($row['status'] ?? 0) === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提现页可选支付渠道(仅返回已启用且已对接出金的渠道)
|
||||
*
|
||||
* @param list<array{code: string, sort: int, status: int, tier_ids: list<string>}> $effectiveRows
|
||||
*
|
||||
* @return list<array{code: string, name: string, sort: int}>
|
||||
*/
|
||||
public static function channelsForWithdraw(array $effectiveRows, string $lang): array
|
||||
{
|
||||
$registry = self::codeRegistry();
|
||||
$allowed = self::withdrawPayoutChannelCodes();
|
||||
$out = [];
|
||||
foreach ($effectiveRows as $row) {
|
||||
if (($row['status'] ?? 0) !== 1) {
|
||||
continue;
|
||||
}
|
||||
$code = isset($row['code']) && is_string($row['code']) ? $row['code'] : '';
|
||||
if ($code === '' || !in_array($code, $allowed, true)) {
|
||||
continue;
|
||||
}
|
||||
if (!isset($registry[$code])) {
|
||||
continue;
|
||||
}
|
||||
$meta = $registry[$code];
|
||||
$sortRaw = $row['sort'] ?? 0;
|
||||
$sortVal = is_numeric($sortRaw) ? intval($sortRaw) : 0;
|
||||
$out[] = [
|
||||
'code' => $code,
|
||||
'name' => self::pickLangName($meta, $lang),
|
||||
'sort' => $sortVal,
|
||||
];
|
||||
}
|
||||
usort($out, static function (array $a, array $b): int {
|
||||
if ($a['sort'] !== $b['sort']) {
|
||||
return $a['sort'] <=> $b['sort'];
|
||||
}
|
||||
|
||||
return strcmp($a['code'], $b['code']);
|
||||
});
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<array<string, mixed>> $items
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user