Files
lotteryLaravel/app/Support/CreditAmountScale.php
kang 6b2ea39ea1
Some checks failed
lotterLaravel CI / test (push) Has been cancelled
fix: 修复并发竞态与幂等性缺陷并优化子树查询
- 扩大玩家ID随机数位宽降低碰撞概率
- 授信额度变更加 lockForUpdate 防并发下调
- 结算冲正与入账利用唯一索引实现幂等闸门
- 失败登录计数加锁防丢失
- 代理子树查询改用子查询替代全表 pluck
- 修复返点默认值百分比单位转换
- 测试中全量 fake 广播事件防 CI 500
2026-06-18 09:38:24 +08:00

66 lines
2.1 KiB
PHP
Raw Permalink 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\Support;
use App\Models\Currency;
use App\Services\LotterySettings;
/**
* 信用占成盘额度(代理/玩家授信、已用)在库内按「主货币整数」存储;
* 彩票下注、钱包 API 使用最小货币单位minor。本类负责二者换算。
*/
final class CreditAmountScale
{
public static function minorUnitFactor(string $currencyCode): int
{
$code = strtoupper(trim($currencyCode));
if ($code === '') {
return (int) max(1, 10 ** LotterySettings::currencyDisplayDecimals());
}
$currency = Currency::query()->where('code', $code)->first();
$decimals = $currency !== null
? (int) $currency->decimal_places
: LotterySettings::currencyDisplayDecimals();
return (int) max(1, 10 ** max(0, min(12, $decimals)));
}
public static function majorToMinor(int $major, string $currencyCode): int
{
// 负值防御:所有调用方都应在传入前 max(0, ...) 兜底available credit / balance / 等),
// 此处 double-check 是兜底而非业务逻辑。若发生负数通常意味着上游计算 bug
// 记录 warning 让 production 暴露问题而不被静默吞掉。
if ($major < 0) {
\Illuminate\Support\Facades\Log::warning('CreditAmountScale::majorToMinor received negative value', [
'major' => $major,
'currency_code' => $currencyCode,
'trace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 4),
]);
return 0;
}
return $major * self::minorUnitFactor($currencyCode);
}
/**
* 最小单位 → 主货币整数(占用授信时向上取整,与 preflight 按 major 校验一致)。
*/
public static function minorToMajor(int $minor, string $currencyCode): int
{
$factor = self::minorUnitFactor($currencyCode);
if ($factor <= 1) {
return $minor;
}
if ($minor <= 0) {
return 0;
}
return intdiv($minor + $factor - 1, $factor);
}
}