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); } }