feat(lottery): 扩展传统马来赔率、玩法结算与开注商短码支持
This commit is contained in:
@@ -16,6 +16,8 @@ final class Pos2TierSettlementMatcher implements SettlementPlayMatcher
|
||||
'pos_2a' => 'first',
|
||||
'pos_2b' => 'second',
|
||||
'pos_2c' => 'third',
|
||||
'pos_2d' => 'starter',
|
||||
'pos_2e' => 'consolation',
|
||||
];
|
||||
|
||||
public function __construct(
|
||||
|
||||
@@ -16,6 +16,8 @@ final class Pos3TierSettlementMatcher implements SettlementPlayMatcher
|
||||
'pos_3a' => 'first',
|
||||
'pos_3b' => 'second',
|
||||
'pos_3c' => 'third',
|
||||
'pos_3d' => 'starter',
|
||||
'pos_3e' => 'consolation',
|
||||
];
|
||||
|
||||
public function __construct(
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Settlement\Matchers;
|
||||
|
||||
use App\Models\TicketItem;
|
||||
use App\Models\TicketCombination;
|
||||
use Illuminate\Support\Collection;
|
||||
use App\Services\Settlement\OddsSnapshotReader;
|
||||
use App\Services\Settlement\PublishedDrawResultBoard;
|
||||
use App\Services\Settlement\Contracts\SettlementPlayMatcher;
|
||||
|
||||
/** Settles aggregate 4D / suffix plays against an explicit group of prize scopes. */
|
||||
final class ScopeFilteredSettlementMatcher implements SettlementPlayMatcher
|
||||
{
|
||||
/** @var array<string, list<string>> */
|
||||
private const SCOPES = [
|
||||
'four_lower' => ['starter', 'consolation'],
|
||||
'pos_3lower' => ['starter', 'consolation'],
|
||||
'pos_2any' => ['first', 'second', 'third', 'starter', 'consolation'],
|
||||
];
|
||||
|
||||
public function __construct(private readonly OddsSnapshotReader $odds) {}
|
||||
|
||||
public function match(TicketItem $item, PublishedDrawResultBoard $board, Collection $combinations): array
|
||||
{
|
||||
$allowed = self::SCOPES[(string) $item->play_code] ?? [];
|
||||
$snapshot = is_array($item->odds_snapshot_json) ? $item->odds_snapshot_json : null;
|
||||
$lines = [];
|
||||
$total = 0;
|
||||
$bestTier = null;
|
||||
|
||||
foreach ($combinations as $combo) {
|
||||
/** @var TicketCombination $combo */
|
||||
$hit = $board->bestTierForNumber((string) $combo->number_4d);
|
||||
if ($hit === null || ! in_array($hit['tier'], $allowed, true)) continue;
|
||||
$oddsValue = $this->odds->oddsValueForScope($snapshot, $hit['tier']);
|
||||
$payout = (int) floor((int) $combo->bet_amount * ($oddsValue / 10_000));
|
||||
$total += $payout;
|
||||
$bestTier ??= $hit['tier'];
|
||||
$lines[] = ['number_4d' => $combo->number_4d, 'tier' => $hit['tier'], 'payout' => $payout];
|
||||
}
|
||||
|
||||
return ['win_amount' => $total, 'matched_prize_tier' => $bestTier, 'match_detail' => ['lines' => $lines]];
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ use App\Services\Settlement\Matchers\Pos4ListTierSettlementMatcher;
|
||||
use App\Services\Settlement\Matchers\StraightLikeSettlementMatcher;
|
||||
use App\Services\Settlement\Matchers\Pos4ExactTierSettlementMatcher;
|
||||
use App\Services\Settlement\Matchers\FirstPrizeComboSettlementMatcher;
|
||||
use App\Services\Settlement\Matchers\ScopeFilteredSettlementMatcher;
|
||||
|
||||
final class SettlementMatcherRegistry
|
||||
{
|
||||
@@ -28,6 +29,7 @@ final class SettlementMatcherRegistry
|
||||
private readonly Pos2TierSettlementMatcher $pos2Tier,
|
||||
private readonly Pos2AbcSettlementMatcher $pos2Abc,
|
||||
private readonly FirstPrizeComboSettlementMatcher $firstPrizeCombo,
|
||||
private readonly ScopeFilteredSettlementMatcher $scopeFiltered,
|
||||
private readonly NoopSettlementMatcher $noop,
|
||||
) {}
|
||||
|
||||
@@ -36,14 +38,15 @@ final class SettlementMatcherRegistry
|
||||
// half_box:PRD 一期预留;结算按已落库组合逐条取 23 档最优档,与 big/box 家族一致(§5.6.6)。
|
||||
return match ($playCode) {
|
||||
'straight', 'roll' => $this->straight,
|
||||
'big', 'ibox', 'mbox', 'box', 'half_box' => $this->big,
|
||||
'small' => $this->small,
|
||||
'big', 'ibox', 'mbox', 'box', 'half_box', 'four_any' => $this->big,
|
||||
'small', 'four_top' => $this->small,
|
||||
'pos_4a', 'pos_4b', 'pos_4c' => $this->pos4Exact,
|
||||
'pos_4d', 'pos_4e' => $this->pos4List,
|
||||
'pos_3a', 'pos_3b', 'pos_3c' => $this->pos3Tier,
|
||||
'pos_3a', 'pos_3b', 'pos_3c', 'pos_3d', 'pos_3e' => $this->pos3Tier,
|
||||
'pos_3abc' => $this->pos3Abc,
|
||||
'pos_2a', 'pos_2b', 'pos_2c' => $this->pos2Tier,
|
||||
'pos_2a', 'pos_2b', 'pos_2c', 'pos_2d', 'pos_2e' => $this->pos2Tier,
|
||||
'pos_2abc' => $this->pos2Abc,
|
||||
'four_lower', 'pos_3lower', 'pos_2any' => $this->scopeFiltered,
|
||||
'head', 'tail', 'odd', 'even', 'digit_big', 'digit_small' => $this->firstPrizeCombo,
|
||||
default => $this->noop,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user