feat: 增强代理结算和账单管理功能

- 在多个控制器中引入 SettlementPartyEnrichment 服务,以优化代理结算和账单的处理逻辑。
- 更新 AgentSettlementBillIndexController 和 AgentSettlementBillShowController,支持根据账单 ID 和关键字进行查询。
- 在 AgentSettlementPeriodCloseController 中添加对站点管理权限的验证,确保只有具备相应权限的管理员能够关闭账期。
- 在 AgentSettlementPeriodIndexController 中更新账期数据的返回格式,提升数据的完整性和可用性。
- 引入对相对占成比例的支持,增强代理资料的管理能力,确保数据一致性。
This commit is contained in:
2026-06-05 18:00:56 +08:00
parent a44679665d
commit 2d32f006c5
63 changed files with 4893 additions and 288 deletions

View File

@@ -0,0 +1,101 @@
<?php
namespace App\Console\Commands;
use App\Models\Player;
use App\Support\PlayerFundingMode;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
final class BackfillCreditSettlementWinsCommand extends Command
{
protected $signature = 'credit:backfill-settlement-wins
{--player-id= : 仅回填指定玩家}
{--ticket-item-id= : 仅回填指定注项}
{--dry-run : 仅输出将回填的数据,不实际写入}';
protected $description = '回填历史信用盘中奖但缺失 credit_ledger 中奖流水的数据';
public function handle(): int
{
$playerId = (int) ($this->option('player-id') ?? 0);
$ticketItemId = (int) ($this->option('ticket-item-id') ?? 0);
$dryRun = (bool) $this->option('dry-run');
$query = DB::table('ticket_items as ti')
->join('players as p', 'p.id', '=', 'ti.player_id')
->leftJoin('credit_ledger as cl', function ($join): void {
$join->on('cl.ref_id', '=', 'ti.id')
->where('cl.owner_type', '=', 'player')
->where('cl.ref_type', '=', 'ticket_item')
->where('cl.reason', '=', 'game_settlement_win');
})
->where('p.funding_mode', PlayerFundingMode::CREDIT)
->where('ti.status', 'settled_win')
->where('ti.win_amount', '>', 0)
->whereNull('cl.id')
->select([
'ti.id',
'ti.player_id',
'ti.win_amount',
'ti.updated_at',
])
->orderBy('ti.id');
if ($playerId > 0) {
$query->where('ti.player_id', $playerId);
}
if ($ticketItemId > 0) {
$query->where('ti.id', $ticketItemId);
}
$rows = $query->get();
if ($rows->isEmpty()) {
$this->info('没有发现需要回填的信用盘中奖流水。');
return self::SUCCESS;
}
$this->info('待回填条数:'.$rows->count());
foreach ($rows as $row) {
$this->line(sprintf(
'ticket_item=%d player=%d win=%d',
(int) $row->id,
(int) $row->player_id,
(int) $row->win_amount,
));
}
if ($dryRun) {
$this->comment('dry-run 模式,未写入任何数据。');
return self::SUCCESS;
}
DB::transaction(function () use ($rows): void {
foreach ($rows as $row) {
$player = Player::query()->find((int) $row->player_id);
if ($player === null || ! PlayerFundingMode::usesCredit($player)) {
continue;
}
DB::table('credit_ledger')->insert([
'owner_type' => 'player',
'owner_id' => (int) $row->player_id,
'amount' => (int) $row->win_amount,
'reason' => 'game_settlement_win',
'ref_type' => 'ticket_item',
'ref_id' => (int) $row->id,
'created_at' => $row->updated_at ?? now(),
'updated_at' => now(),
]);
}
});
$this->info('回填完成。');
return self::SUCCESS;
}
}