refactor: 更新权限管理与请求验证逻辑

- 在多个控制器中将权限检查从 hasAdminPermission 更新为 hasPermissionCode,以增强权限管理的灵活性。
- 引入 AdminScopePolicy,优化基于代理节点的权限和数据过滤逻辑,确保管理员能够更精确地控制访问权限。
- 在请求验证中添加 agent_node_id 字段,确保 API 接口支持代理节点的相关操作。
- 更新 AdminUser 模型,新增 hasPermissionCode 方法,以支持更细粒度的权限检查。
- 优化审计日志记录逻辑,确保在处理请求时能够准确记录管理员的操作。
This commit is contained in:
2026-06-03 10:07:38 +08:00
parent 0841fbed32
commit 1dcd4716c5
64 changed files with 2054 additions and 344 deletions

View File

@@ -37,7 +37,7 @@ final class LotteryTransferService
/** PRD §12对账后冲正 */
private const ST_REVERSED = 'reversed';
/** PRD §12对账后人工处理 */
/** PRD §12对账后标记结案(仅改状态,不动钱包) */
private const ST_MANUALLY_PROCESSED = 'manually_processed';
private const BIZ_TRANSFER_IN = 'transfer_in';
@@ -326,10 +326,10 @@ final class LotteryTransferService
}
/**
* 对账操作:冲正 / 人工处理
* 对账操作:冲正 / 补入账 / 标记结案
*
* 冲正reverse主站确认未成功对已扣彩票余额的转出单做反向操作加回余额标记为已冲正。
* 人工处理manually_process管理员确认该订单已通过其它途径解决,仅标记状态,不动钱包。
* 标记结案manually_process确认已在系统外处理完毕,仅改订单状态,不动钱包。
*
* @param 'reverse'|'manually_process' $action
* @throws WalletOperationException
@@ -402,6 +402,30 @@ final class LotteryTransferService
deltaSign: 1,
);
}
} elseif ($this->isEligibleForTransferInReverse($locked)) {
$player = Player::query()->whereKey($locked->player_id)->firstOrFail();
$refund = $this->mainSite->refundMainForFailedLotteryDeposit(
$player,
(string) $locked->currency_code,
(int) $locked->amount,
'refund:'.$locked->transfer_no,
);
if (! $refund->ok) {
throw new WalletOperationException(
$refund->errorMessage ?? 'main_site_refund_failed',
$refund->uncertain
? ErrorCode::WalletTransferPending->value
: ErrorCode::WalletExternalRejected->value,
$refund->uncertain ? 409 : 422,
);
}
$locked->forceFill([
'external_request_payload' => $refund->requestPayload,
'external_response_payload' => $refund->responsePayload,
'external_ref_no' => $refund->externalRefNo ?? $locked->external_ref_no,
])->save();
}
$locked->forceFill([
@@ -510,6 +534,14 @@ final class LotteryTransferService
);
}
if (! $this->isEligibleForManualProcess($locked)) {
throw new WalletOperationException(
'manually_process_not_eligible',
ErrorCode::WalletExternalRejected->value,
422,
);
}
$locked->forceFill([
'status' => self::ST_MANUALLY_PROCESSED,
'fail_reason' => 'manually_processed: '.($remark ?: 'admin_manual'),
@@ -518,12 +550,32 @@ final class LotteryTransferService
}
/** 仅主站已扣款(有 external_ref_no且彩票入账失败时可补完成转入。 */
private function isEligibleForCompleteCredit(TransferOrder $order): bool
public function isEligibleForCompleteCredit(TransferOrder $order): bool
{
return $order->fail_reason === 'lottery_credit_failed'
&& trim((string) $order->external_ref_no) !== '';
}
public function isEligibleForTransferInReverse(TransferOrder $order): bool
{
return $order->direction === self::DIR_IN
&& $order->status === self::ST_PENDING_RECONCILE
&& $this->isEligibleForCompleteCredit($order);
}
public function isEligibleForManualProcess(TransferOrder $order): bool
{
if (! in_array($order->status, [self::ST_PROCESSING, self::ST_FAILED, self::ST_PENDING_RECONCILE], true)) {
return false;
}
if ($order->direction === self::DIR_OUT && $order->status === self::ST_PENDING_RECONCILE) {
return false;
}
return $order->fail_reason !== 'lottery_credit_failed';
}
private function lockLotteryWalletById(int $playerId, string $currencyCode): PlayerWallet
{
$wallet = PlayerWallet::query()