feat: 对接越南AlinPay支付网关(代收+代付)

- 新增 AlinPay 网关核心类:签名/验签/代收/代付/查询/账户接口
- 新增 alinPay trait:充值发起 + 代收回调结算(事务+行锁)
- 修改 admin/agent Report:提现审批自动路由 ALIN_VN 发起代付
- 新增 Pcapi:银行卡提现申请 + 越南银行列表接口
- 修改 Crypto:代付回调/订单查询/账户查询入口
- 新增越南区 area_list(id=3) + alinPay pay_list 配置
- DDL: user_withdraw 表增加 pay_channel/ext 字段
This commit is contained in:
li
2026-03-12 22:24:49 +08:00
parent e633c8e27d
commit 79123e079f
9 changed files with 997 additions and 13 deletions
+115
View File
@@ -3966,6 +3966,121 @@ class Pcapi extends Controller{
}
// 申请银行卡提现(越南AlinPay)
public function apply_withdraw_bank(){
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Headers: token, Origin, X-Requested-With, Content-Type, Accept, Authorization");
header('Access-Control-Allow-Methods: POST,GET,PUT,DELETE');
if(Request::instance()->isPost()){
$json_arr = decrypt_data(Request::instance()->post());
if($json_arr){
$userId = intval($json_arr['user_id']);
$amount = floatval($json_arr['amount']);
$accountName = trim($json_arr['account_name'] ?? '');
$accountNumber = trim($json_arr['account_number'] ?? '');
$bankCode = trim($json_arr['bank_code'] ?? '');
$bankName = trim($json_arr['bank_name'] ?? '');
if(!$amount || $amount <= 0){
return json(array('Success' => 0, 'Msg' => 'Số tiền rút không hợp lệ'));
}
if(empty($accountName)){
return json(array('Success' => 0, 'Msg' => 'Tên tài khoản không được để trống'));
}
if(empty($accountNumber)){
return json(array('Success' => 0, 'Msg' => 'Số tài khoản không được để trống'));
}
if(empty($bankName)){
return json(array('Success' => 0, 'Msg' => 'Tên ngân hàng không được để trống'));
}
$user = Db::name('user')->where(array('id' => $userId))->find();
if($user){
Db::startTrans();
$user = Db::name('user')->where(array('id' => $userId))->lock(true)->find();
$system = Db::name('system')->find();
$money = $user['money'];
$withdrawMoney = empty($system['withdraw_money']) ? 100 : $system['withdraw_money'];
$withdrawFee = empty($system['withdraw_fee']) ? 1 : $system['withdraw_fee'];
// 计算积分兑换
$amountMoney = $withdrawMoney/100*($amount);
$feeMoney = $withdrawMoney/100*($withdrawFee);
$needMoney = $amountMoney + $feeMoney;
if($needMoney > $money){
Db::rollback();
return json(array('Success' => 0, 'Msg' => 'Số dư không đủ'));
}
$afterMoney = $money - $needMoney;
// 银行卡信息存入ext
$ext = json_encode([
'accountName' => $accountName,
'accountNumber' => $accountNumber,
'bankCode' => $bankCode,
'bankName' => $bankName,
], JSON_UNESCAPED_UNICODE);
// 写入提现申请
$res = Db::name('user_withdraw')->insert([
'order_no' => createOrderNo('TX'),
'user_id' => $userId,
'amount' => $amount,
'money' => $amountMoney,
'old_money' => $money,
'new_money' => $afterMoney,
'service_fee' => $withdrawFee,
'service_fee_money' => $feeMoney,
'withdraw_rate' => $withdrawFee,
'to_address' => $accountNumber,
'pay_channel' => 'ALIN_VN',
'ext' => $ext,
'create_time' => time()
]);
if(!$res){
Db::rollback();
return json(array('Success' => 0, 'Msg' => 'Thao tác thất bại'));
}
// 扣除用户余额
$res = Db::name('user')->where('id',$userId)->update([
'money' => $afterMoney,
'update_time' => time()
]);
if(!$res){
Db::rollback();
return json(array('Success' => 0, 'Msg' => 'Thao tác thất bại'));
}
Db::commit();
return json(array('Success' => 1, 'Msg' => 'Thành công, vui lòng chờ xử lý'));
}else{
return json(array('Success' => 0, 'Msg' => 'Lấy thông tin thất bại'));
}
}
}
}
// 获取越南银行列表
public function get_bank_list_vn(){
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Headers: token, Origin, X-Requested-With, Content-Type, Accept, Authorization");
header('Access-Control-Allow-Methods: POST,GET,PUT,DELETE');
$banks = \pay\AlinPay::getBankCodes();
$list = [];
foreach($banks as $index => $name){
if(!empty($name)){
$list[] = [
'code' => $name,
'name' => $name,
];
}
}
return json(array('Success' => 1, 'Data' => $list));
}
// 取消提现
public function cancel_withdraw(){
header('Access-Control-Allow-Origin: *');