post(); if (isset($post['encryptData'])) { $post = decrypt_data($post); if (!$post) { $data = encrypt_data(['status' => 0, 'message' => 'Dữ liệu không hợp lệ']); return json(['Success' => 1, 'Data' => $data]); } } $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) { $data = encrypt_data(['status' => 0, 'message' => 'Tham số không hợp lệ, vui lòng thử lại']); return json(['Success' => 1, 'Data' => $data]); } $zdlIdArr = explode(',', $user['agent_parent_id_path']); $area_list = config('area_list'); if (!isset($area_list[$user['area_id']])) { $data = encrypt_data(['status' => 0, 'message' => 'Khu vực hiện chưa hỗ trợ nạp tiền']); return json(['Success' => 1, 'Data' => $data]); } $limitAgents = $area_list[$user['area_id']]['limit_agent']; $isAllow = empty($limitAgents); foreach ($limitAgents as $allowAgentId) { if (in_array($allowAgentId, $zdlIdArr)) { $isAllow = true; } } if (!$isAllow) { $data = encrypt_data(['status' => 0, 'message' => 'Tài khoản này chưa được phép nạp online']); return json(['Success' => 1, 'Data' => $data]); } $zdlId = $zdlIdArr[0]; $zdl = Db::name('user')->where([ 'id' => $zdlId, 'status' => 1, 'is_delete' => 0, 'agent' => 1, ])->find(); if (!$zdl) { $data = encrypt_data(['status' => 0, 'message' => 'Tài khoản đại lý có vấn đề, không thể nạp']); return json(['Success' => 1, 'Data' => $data]); } if ($zdl['money'] < $money) { $maxAllowed = intval($zdl['money']); $data = encrypt_data([ 'status' => 0, 'code' => 'AGENT_LIMIT', 'message' => 'Hạn mức nạp mỗi lần hiện tại là ' . number_format($maxAllowed, 0, '.', ',') . ' VND. Vui lòng nhập số tiền nhỏ hơn hoặc bằng mức trên.', 'max_amount' => $maxAllowed, ]); return json(['Success' => 1, 'Data' => $data]); } $pay_list = config('pay_list'); $pay_orderid = 'C' . date('YmdHis') . rand(100000, 999999); $notify_url = $pay_list['ccpay']['notify_url'] ?? ''; $timeout = intval($pay_list['ccpay']['timeout'] ?? 600); try { $ccpay = new \pay\Ccpay(); $result = $ccpay->createOrder( $pay_orderid, sprintf('%.0f', $money), $notify_url, 'uid_' . $user_id ); if (!is_array($result)) { addLogToFile('ccpay 下单: API 无响应', 'ccpay_error', 'ccpay'); $data = encrypt_data(['status' => 0, 'message' => 'Kênh thanh toán không phản hồi, vui lòng thử lại']); return json(['Success' => 1, 'Data' => $data]); } $status = intval($result['status'] ?? -1); $resultCode = intval($result['resultCode'] ?? -1); if ($status !== 0 || $resultCode !== 0) { $errMsg = $result['errMsg'] ?? 'Lỗi không xác định'; addLogToFile('ccpay 下单失败: order=' . $pay_orderid . ' err=' . $errMsg . ' raw=' . json_encode($result, JSON_UNESCAPED_UNICODE), 'ccpay_error', 'ccpay'); $data = encrypt_data(['status' => 0, 'message' => 'Khởi tạo thanh toán thất bại: ' . $errMsg]); return json(['Success' => 1, 'Data' => $data]); } $order_id = Db::name('order_record')->insertGetId([ 'pay_channel_id' => 9, 'pay_channel_name' => 'ccpay', 'user_id' => $user_id, 'order_sn' => $pay_orderid, 'appid' => $ccpay->getConfigInfo()['mch_no'] ?? '', 'api_key' => '', 'money' => $money, 'sign' => '', 'create_time' => time(), 'back_order_sn' => $result['cpOrderNo'] ?? '', 'client' => $client, ]); Db::name('order_log')->insert([ 'pay_channel_id' => 9, 'pay_channel_name' => 'ccpay', 'money' => $money, 'create_time' => time(), 'remake' => 'user_id:' . $user_id . ',用户名:' . $username . ',CCpay发起充值:' . $money . ',时间:' . date('Y-m-d H:i:s'), 'order_id' => $order_id, 'client' => $client, ]); $codeUrl = $result['codeUrl'] ?? ''; $qrcode = null; $msgJson = $result['message'] ?? ''; if ($msgJson) { $bankInfo = json_decode($msgJson, true); if (is_array($bankInfo) && !empty($bankInfo['AccNo'])) { $expiresAt = time() + $timeout; $qrcode = [ 'order_sn' => $pay_orderid, 'bank_account' => $bankInfo['AccNo'] ?? '', 'bank_name' => $bankInfo['AccName'] ?? '', 'bank_branch' => $bankInfo['Branch'] ?? '', 'bank_short' => $bankInfo['BankShortName'] ?? '', 'qr_data' => $bankInfo['qrcode'] ?? '', 'remark' => $bankInfo['remark'] ?? '', 'amount' => $money, 'expires_at' => $expiresAt, 'timeout_sec' => $timeout, ]; } } addLogToFile('ccpay 下单成功: order=' . $pay_orderid . ' cp=' . ($result['cpOrderNo'] ?? ''), 'ccpay_request', 'ccpay'); $data = encrypt_data([ 'status' => 1, 'message' => 'Khởi tạo thanh toán thành công', 'url' => $codeUrl, 'qrcode' => $qrcode, ]); return json(['Success' => 1, 'Data' => $data]); } catch (\Exception $e) { addLogToFile('ccpay 下单异常: ' . $e->getMessage() . ' | file:' . $e->getFile() . ':' . $e->getLine(), 'ccpay_error', 'ccpay'); $data = encrypt_data(['status' => 0, 'message' => 'Khởi tạo thanh toán thất bại: ' . $e->getMessage()]); return json(['Success' => 1, 'Data' => $data]); } } public function ccpay_order_status() { $post = Request::instance()->post(); if (isset($post['encryptData'])) { $post = decrypt_data($post); if (!$post) { return json(['status' => 0, 'message' => '数据解密失败']); } } $order_sn = trim($post['order_sn'] ?? ''); $user_id = intval($post['user_id'] ?? 0); if ($order_sn === '' || $user_id <= 0) { $data = encrypt_data(['status' => 0, 'message' => '参数错误']); return json(['Success' => 1, 'Data' => $data]); } $order = Db::name('order_record') ->where([ 'order_sn' => $order_sn, 'user_id' => $user_id, 'pay_channel_id' => 9, ]) ->find(); if (!$order) { $data = encrypt_data(['status' => 0, 'message' => '订单不存在']); return json(['Success' => 1, 'Data' => $data]); } if (intval($order['status']) == 3) { $data = encrypt_data([ 'status' => 1, 'message' => 'Nạp tiền thành công', 'money' => $order['money'], 'paid_time' => $order['back_time'], ]); return json(['Success' => 1, 'Data' => $data]); } $pay_list = config('pay_list'); $timeout = intval($pay_list['ccpay']['timeout'] ?? 600); if (time() - intval($order['create_time']) > $timeout) { $data = encrypt_data([ 'status' => 2, 'message' => 'Đơn hàng đã hết hạn', 'money' => $order['money'], ]); return json(['Success' => 1, 'Data' => $data]); } $data = encrypt_data([ 'status' => 0, 'message' => 'Đang chờ thanh toán', 'money' => $order['money'], ]); return json(['Success' => 1, 'Data' => $data]); } public function ccpay_recharge_callback() { $raw = file_get_contents('php://input'); $post = json_decode($raw, true); if (!$post) { $post = Request::instance()->post(); } $json = json_encode($post, JSON_UNESCAPED_UNICODE); addLogToFile('ccpay 回调原始数据: ' . $json, 'ccpay_callback', 'ccpay'); if (!is_array($post) || empty($post['mchOrderNo']) || empty($post['sign'])) { Log::record($post, 'ccpay_error_callback'); exit('fail'); } $logId = Db::name('pay_callback_log')->insertGetId([ 'pay_channel' => 'CCPAY_RECHARGE', 'type' => 'recharge', 'json' => $json, 'create_time' => date('Y-m-d H:i:s'), ]); try { $ccpay = new \pay\Ccpay(); $verifyData = []; $verifyData['status'] = strval($post['status'] ?? ''); $verifyData['mchNo'] = $post['mchNo'] ?? ''; $verifyData['resultCode'] = strval($post['resultCode'] ?? ''); $verifyData['cpOrderNo'] = $post['cpOrderNo'] ?? ''; $verifyData['mchOrderNo'] = $post['mchOrderNo'] ?? ''; $verifyData['amount'] = strval($post['amount'] ?? ''); $verifyData['payResult'] = $post['payResult'] ?? ''; $verifyData['traceTime'] = $post['traceTime'] ?? ''; $verifyData['message'] = $post['message'] ?? ''; $signData = array_filter($verifyData, function ($v) { return $v !== '' && $v !== null; }); $signData['sign'] = $post['sign']; if (!$ccpay->verifySign($signData)) { addLogToFile('ccpay 回调验签失败: ' . $json, 'ccpay_callback_error', 'ccpay'); exit('fail'); } if ($logId && !empty($post['mchOrderNo'])) { Db::name('pay_callback_log')->where('id', $logId)->update(['unique_no' => $post['mchOrderNo']]); } $payResult = strval($post['payResult'] ?? ''); if ($payResult === '0') { $this->ccpay_recharge_settle($post); addLogToFile('ccpay 回调成功: order=' . $post['mchOrderNo'], 'ccpay_callback', 'ccpay'); exit('success'); } else { addLogToFile('ccpay 回调非成功状态: payResult=' . $payResult . ' order=' . $post['mchOrderNo'], 'ccpay_callback', 'ccpay'); exit('success'); } } catch (\Exception $e) { addLogToFile('ccpay 回调异常: ' . $e->getMessage(), 'ccpay_callback_error', 'ccpay'); exit('fail'); } } private function ccpay_recharge_settle($data) { $orderNo = $data['mchOrderNo']; 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('ccpay 结算失败: 代理余额不足 order=' . $orderNo, 'ccpay_callback_error', 'ccpay'); return; } $actualMoney = isset($data['amount']) ? intval($data['amount']) : $order['money']; Db::name('order_record')->where('id', $order['id'])->update([ 'back_money' => $actualMoney, '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'], ]); Db::name('order_log')->insert([ 'pay_channel_id' => 9, 'pay_channel_name' => 'ccpay', 'money' => $order['money'], 'create_time' => time(), 'remake' => 'CCpay回调成功 cp=' . ($data['cpOrderNo'] ?? '') . ' payer=' . ($data['message'] ?? ''), 'order_id' => $order['id'], ]); 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' => 'CCpay越南银行第三方充值,扣取总代理余分', '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' => 'CCpay越南银行第三方充值成功', ]); 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'], ]); 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('ccpay 结算成功: order=' . $orderNo . ' money=' . $order['money'], 'ccpay_callback', 'ccpay'); } catch (\Exception $e) { Db::rollback(); addLogToFile('ccpay 结算异常: ' . $e->getMessage(), 'ccpay_callback_error', 'ccpay'); } } }