Files
webman-buildadmin/app/common/library/finance/MockPay.php
zhenhui 1b8d947f97 0.使用模拟数据进行充值和提现
1.优化提现接口/api/finance/withdrawCreate
2.优化充值接口/api/finance/depositCreate
2026-05-20 15:57:19 +08:00

364 lines
6.0 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
declare(strict_types=1);
namespace app\common\library\finance;
use app\common\service\DepositOrderExpireService;
/**
* 模拟支付(无真实商户网关):用于开发/联调充值与提现审核。
*/
final class MockPay
{
public const CHANNEL_CODE = 'mock';
/** 待审核(用户已在模拟页确认支付,等待后台审核) */
public const DEPOSIT_STATUS_PENDING_REVIEW = 3;
public static function isEnabled(): bool
{
$raw = getenv('FINANCE_MOCK_PAY_ENABLED');
if (is_string($raw) && trim($raw) !== '') {
$norm = strtolower(trim($raw));
if (in_array($norm, ['0', 'false', 'no', 'off'], true)) {
return false;
}
if (in_array($norm, ['1', 'true', 'yes', 'on'], true)) {
return true;
}
}
$cfg = config('app.finance_mock_pay_enabled', null);
if ($cfg === true) {
return true;
}
if ($cfg === false) {
return false;
}
$debugRaw = getenv('APP_DEBUG');
if (is_string($debugRaw) && trim($debugRaw) !== '') {
return in_array(strtolower(trim($debugRaw)), ['1', 'true', 'yes', 'on'], true);
}
return false;
}
/**
* 提现审核后是否走模拟出金(不调用 DDPay
* - pay_channel=mock始终模拟
* - FINANCE_MOCK_PAY_ENABLED 开启ddpay/空 一律模拟(审核通过即成功);
* - 未开启 mock 且未配置 DDPayddpay/空 也模拟,避免误调网关。
*/
public static function shouldSimulateWithdrawPayout(string $payChannel): bool
{
$ch = strtolower(trim($payChannel));
if ($ch === self::CHANNEL_CODE) {
return true;
}
if ($ch !== '' && $ch !== 'ddpay') {
return false;
}
if (self::isEnabled()) {
return true;
}
return !DDPayGateway::isConfigured();
}
/**
* 计算链接过期时间与签名(防猜单号)
*
* @return array{expire_at: int, sign: string}
*/
public static function buildDepositLinkAuth(string $orderNo, int $createTime): array
{
$expireAt = $createTime + DepositOrderExpireService::pendingExpireSeconds();
return [
'expire_at' => $expireAt,
'sign' => self::signDepositLink($orderNo, $expireAt),
];
}
public static function signDepositLink(string $orderNo, int $expireAt): string
{
$params = [
'expire_at' => strval($expireAt),
'order_no' => $orderNo,
'secret' => self::linkSecret(),
];
ksort($params);
$pairs = [];
foreach ($params as $key => $value) {
$pairs[] = $key . '=' . $value;
}
return strtoupper(md5(implode('&', $pairs)));
}
public static function verifyDepositLink(string $orderNo, int $expireAt, string $sign): bool
{
$signNorm = strtoupper(trim($sign));
if ($signNorm === '' || $orderNo === '' || $expireAt <= 0) {
return false;
}
return hash_equals(self::signDepositLink($orderNo, $expireAt), $signNorm);
}
/**
* 前端静态收银台 URL优先于服务端内联页
*
* @param string $amountDisplay 2 位小数字符串,供页面展示
* @param string $bonusDisplay 2 位小数字符串
*/
public static function depositPageUrl(
string $orderNo,
string $publicOrigin,
int $expireAt,
string $sign,
string $amountDisplay = '',
string $bonusDisplay = ''
): string {
$htmlBase = self::resolveHtmlBase($publicOrigin);
$apiBase = rtrim($publicOrigin, '/');
$query = [
'order_no' => $orderNo,
'expire_at' => strval($expireAt),
'sign' => $sign,
'api_base' => $apiBase,
];
if ($amountDisplay !== '') {
$query['amount'] = $amountDisplay;
}
if ($bonusDisplay !== '') {
$query['bonus'] = $bonusDisplay;
}
return $htmlBase . '/mock-deposit.html?' . http_build_query($query, '', '&', PHP_QUERY_RFC3986);
}
/**
* 模拟页内确认支付接口(无需 auth-token须携带 sign + expire_at
*/
public static function depositConfirmUrl(string $orderNo, string $publicOrigin, int $expireAt, string $sign): string
{
$base = rtrim($publicOrigin, '/');
$query = http_build_query([
'order_no' => $orderNo,
'expire_at' => strval($expireAt),
'sign' => $sign,
], '', '&', PHP_QUERY_RFC3986);
return $base . '/api/finance/mockDepositConfirm?' . $query;
}
/**
* 解析前端静态页根地址MOCK_DEPOSIT_HTML_BASE > DDPAY_PUBLIC_BASE_URL > API 公网根
*/
public static function resolveHtmlBase(string $publicOrigin): string
{
$raw = getenv('MOCK_DEPOSIT_HTML_BASE');
if (is_string($raw) && trim($raw) !== '') {
return rtrim(trim($raw), '/');
}
$ddpayPublic = getenv('DDPAY_PUBLIC_BASE_URL');
if (is_string($ddpayPublic) && trim($ddpayPublic) !== '') {
return rtrim(trim($ddpayPublic), '/');
}
$cfg = config('app.ddpay_public_base_url', '');
if (is_string($cfg) && trim($cfg) !== '') {
return rtrim(trim($cfg), '/');
}
return rtrim($publicOrigin, '/');
}
private static function linkSecret(): string
{
$raw = getenv('FINANCE_MOCK_PAY_LINK_SECRET');
if (is_string($raw) && trim($raw) !== '') {
return trim($raw);
}
$auth = getenv('AUTH_TOKEN_SECRET');
if (is_string($auth) && trim($auth) !== '') {
return trim($auth);
}
return 'mock-deposit-link-dev-secret';
}
}