Files
Pro/application/onlinechip/controller/traits/alinPay.php
T
OG Backup 171f8fce5c backup: 线上最终版本全量备份
包含所有线上运行的改动:
- 代理编辑功能修复(码率/占成/返水率保存)
- CORS跨域修复(Pcapi构造函数统一Origin)
- 支付通道(ccpay/epay新增)
- 代理报表洗码量显示
- AlinPay金额调整
- 代理/会员编辑页面优化
- 多语言更新
2026-06-14 14:19:49 +08:00

317 lines
13 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace app\onlinechip\controller\traits;
use think\Db;
use think\Log;
use think\Request;
/**
* AlinPay 越南支付 Trait
* 仅包含代收(充值)相关方法
* 代付回调在 Crypto.php 中处理
*/
trait alinPay
{
/**
* 越南代收 - 发起充值
*/
public function alin_online_order()
{
// 兼容加密请求(Pcapi)和明文请求(Order)
$post = Request::instance()->post();
if (isset($post['encryptData'])) {
$post = decrypt_data($post);
if (!$post) {
return json(['status' => 0, 'message' => '数据解密失败']);
}
}
$user_id = intval($post['user_id'] ?? 0);
$money = intval($post['price'] ?? 0);
$client = intval($post['client'] ?? 0);
$username = trim($post['username'] ?? '');
$user = Db::name('user')->where([
'id' => $user_id,
'status' => 1,
'is_delete' => 0,
'agent' => 0,
])->find();
if (!$user || $user_id <= 0 || $money <= 0 || $client <= 0) {
return json(['status' => 0, 'message' => '参数错误,请稍后再试']);
}
// 判断地区支线权限
$zdlIdArr = explode(',', $user['agent_parent_id_path']);
$area_list = config('area_list');
if (!isset($area_list[$user['area_id']])) {
return json(['status' => 0, 'message' => '所在地区暂不支持充值']);
}
$limitAgents = $area_list[$user['area_id']]['limit_agent'];
$isAllow = empty($limitAgents);
foreach ($limitAgents as $allowAgentId) {
if (in_array($allowAgentId, $zdlIdArr)) {
$isAllow = true;
}
}
if (!$isAllow) {
return json(['status' => 0, 'message' => '该账号暂不支持在线充值']);
}
// 验证总代理余额
$zdlId = $zdlIdArr[0];
$zdl = Db::name('user')->where([
'id' => $zdlId,
'status' => 1,
'is_delete' => 0,
'agent' => 1,
])->find();
if (!$zdl) {
return json(['status' => 0, 'message' => '所属代理账号异常,暂不能充值']);
}
if ($zdl['money'] < $money) {
return json(['status' => 0, 'message' => '所属代理余额不足,暂不能充值']);
}
$pay_list = config('pay_list');
$pay_orderid = 'E' . date("YmdHis") . rand(100000, 999999);
$notify_url = $pay_list['alinPay']['notify_url'];
try {
$alinPay = new \pay\AlinPay();
$result = $alinPay->createOrder($pay_orderid, sprintf('%.2f', $money), $notify_url, 'uid:' . $user_id);
// 空响应处理(curl失败/DNS/超时等)
if (!is_array($result)) {
addLogToFile('代收下单:API无响应或返回非JSONresult=' . var_export($result, true), 'alin_error', 'alin');
$data = encrypt_data(['status' => 0, 'message' => '支付通道无响应,请稍后再试']);
return json(array('Success' => 1, 'Data' => $data));
}
if (isset($result['code']) && $result['code'] == 200) {
$returnUrl = $result['data']['url'] ?? '';
if (!$returnUrl) {
$data = encrypt_data(['status' => 0, 'message' => '支付地址获取失败']);
return json(array('Success' => 1, 'Data' => $data));
}
// 记录订单
$order_record = [
'pay_channel_id' => 7,
'pay_channel_name' => 'alinPay',
'user_id' => $user_id,
'order_sn' => $pay_orderid,
'appid' => $alinPay->getConfigInfo()['app_id'],
'api_key' => '',
'money' => $money,
'sign' => '',
'create_time' => time(),
'back_order_sn' => '',
'client' => $client,
];
$order_id = Db::name('order_record')->insertGetId($order_record);
// 记录日志
Db::name('order_log')->insert([
'pay_channel_id' => 7,
'pay_channel_name' => 'alinPay',
'money' => $money,
'create_time' => time(),
'remake' => 'user_id:' . $user_id . ',用户名:' . $username . ',发起充值:' . $money . ',充值时间:' . date('Y-m-d H:i:s'),
'order_id' => $order_id,
'client' => $client,
]);
$data = encrypt_data(['status' => 1, 'message' => '发起支付成功,即将跳转...', 'url' => $returnUrl]);
return json(array('Success' => 1, 'Data' => $data));
} else {
$errMsg = isset($result['message']) ? $result['message'] : '未知错误(code=' . ($result['code'] ?? 'null') . ')';
addLogToFile('代收下单失败:' . json_encode($result, JSON_UNESCAPED_UNICODE), 'alin_error', 'alin');
$data = encrypt_data(['status' => 0, 'message' => '支付发起失败:' . $errMsg]);
return json(array('Success' => 1, 'Data' => $data));
}
} catch (\Exception $e) {
addLogToFile('代收下单异常:' . $e->getMessage() . ' | file:' . $e->getFile() . ':' . $e->getLine(), 'alin_error', 'alin');
$data = encrypt_data(['status' => 0, 'message' => '支付发起失败[' . $e->getMessage() . ']']);
return json(array('Success' => 1, 'Data' => $data));
}
}
/**
* 越南代收 - 回调处理
*/
public function alin_recharge_callback()
{
$post = Request::instance()->post();
$json = json_encode($post, JSON_UNESCAPED_UNICODE);
addLogToFile('代收回调原始数据:' . $json, 'alin_callback', 'alin');
if (!is_array($post) || empty($post['out_trade_no']) || empty($post['sign'])) {
Log::record($post, 'alin_error_callback');
exit('fail');
}
// 记录回调日志
$logId = Db::name('pay_callback_log')->insertGetId([
'pay_channel' => 'ALIN_RECHARGE',
'type' => 'recharge',
'json' => $json,
'create_time' => date('Y-m-d H:i:s'),
]);
try {
$alinPay = new \pay\AlinPay();
$result = $alinPay->verifyRechargeCallback($post, $logId);
if (!$result['verified']) {
exit('fail');
}
$tradeStatus = $result['trade_status'];
// trade_status: 1=成功, -1=处理中, 2=失败
if ($tradeStatus === 1) {
$this->alin_recharge_settle($post);
exit('success');
} elseif ($tradeStatus === 2) {
// 失败,终态,确认收到
addLogToFile('代收回调失败:order=' . $post['out_trade_no'], 'alin_callback', 'alin');
exit('success');
} else {
// 处理中(-1),不返回success让网关重试
exit('fail');
}
} catch (\Exception $e) {
addLogToFile('代收回调处理异常:' . $e->getMessage(), 'alin_callback_error', 'alin');
exit('fail');
}
}
/**
* 代收成功后结算(事务保护:扣代理、写recharge表、加用户余额)
*/
private function alin_recharge_settle($data)
{
$orderNo = $data['out_trade_no'];
Db::startTrans();
try {
// 加锁读取订单,防止重复处理
$order = Db::name('order_record')->where('order_sn', $orderNo)->lock(true)->find();
if (!$order || $order['status'] == 3) {
Db::rollback();
return;
}
// 加锁读取用户
$user = Db::name('user')->where([
'id' => $order['user_id'],
'status' => 1,
'is_delete' => 0,
'agent' => 0,
])->lock(true)->find();
if (!$user) {
Db::rollback();
return;
}
$zdlIdArr = explode(',', $user['agent_parent_id_path']);
$zdlId = $zdlIdArr[0];
// 加锁读取总代理
$zdl = Db::name('user')->where([
'id' => $zdlId,
'status' => 1,
'is_delete' => 0,
'agent' => 1,
])->lock(true)->find();
if (!$zdl || $zdl['money'] < $order['money']) {
Db::rollback();
addLogToFile('代收结算失败:代理余额不足 order=' . $orderNo, 'alin_callback_error', 'alin');
return;
}
// 1. 更新订单状态为已完成
Db::name('order_record')->where('id', $order['id'])->update([
'back_money' => $data['real_amount'] ?: $data['amount'],
'back_time' => time(),
'status' => 3,
'agent_parent_id' => $user['agent_parent_id'],
'agent_parent_username' => $user['agent_parent_username'],
'zdl_id' => $zdl['id'],
'zdl_username' => $zdl['username'],
'zdl_money_before' => $zdl['money'],
'zdl_money_after' => $zdl['money'] - $order['money'],
'money_before' => $user['money'],
'money_after' => $user['money'] + $order['money'],
]);
// 2. 记录日志
Db::name('order_log')->insert([
'pay_channel_id' => 7,
'pay_channel_name' => 'alinPay',
'money' => $order['money'],
'create_time' => time(),
'remake' => '回调支付成功',
'order_id' => $order['id'],
]);
// 3. 写recharge流水表
Db::name('recharge')->insert([
'type' => 4,
'amount' => $order['money'],
'mode' => 1,
'agent_or_admin' => 3,
'controller_id' => $zdl['id'],
'controller_username' => $zdl['username'],
'controller_nickname' => $zdl['nickname'],
'controller_type' => '越南第三方充值平台充值,扣取总代理余分',
'controller_old_money' => $zdl['money'],
'controller_new_money' => $zdl['money'] - $order['money'],
'user_id' => $order['user_id'],
'user_type' => $user['agent'],
'user_agent_level' => 0,
'username_for' => $user['username'],
'nickname_for' => $user['nickname'],
'user_parent_id' => $user['agent_parent_id'],
'create_time' => time(),
'old_money' => $user['money'],
'new_money' => $user['money'] + $order['money'],
'controller_system' => 3,
'remake' => '越南AlinPay第三方充值成功',
]);
// 4. 扣代理余额
Db::name('user')->where('id', $zdl['id'])->update([
'money' => $zdl['money'] - $order['money'],
'last_recharge_out' => $order['money'],
'last_recharge_out_time' => time(),
'recharge_out_count' => $zdl['recharge_out_count'] + 1,
'recharge_out_total_amount' => $zdl['recharge_out_total_amount'] + $order['money'],
]);
// 5. 给用户加余额
Db::name('user')->where('id', $order['user_id'])->update([
'money' => $user['money'] + $order['money'],
'last_recharge' => $order['money'],
'last_recharge_time' => time(),
'recharge_count' => $user['recharge_count'] + 1,
'recharge_total_amount' => $user['recharge_total_amount'] + $order['money'],
]);
Db::commit();
addLogToFile('代收结算成功:order=' . $orderNo . ' money=' . $order['money'], 'alin_callback', 'alin');
} catch (\Exception $e) {
Db::rollback();
addLogToFile('代收结算异常:' . $e->getMessage(), 'alin_callback_error', 'alin');
}
}
}