feat: add idempotency support for settlement adjustments and payments, fix rebate handling
Some checks failed
lotterLaravel CI / test (push) Has been cancelled
lotterLaravel E2E / e2e-api (push) Has been cancelled

- Added idempotency_key parameter to settlement bill adjustment and payment endpoints to prevent duplicate operations
- Fixed player rebate profile updates to preserve existing values when only one field is modified
- Moved wallet player validation earlier in AdminPlayerStoreController to prevent unnecessary processing
- Enhanced extra rebate calculation to include 'in_bill' and 'settled' statuses in AgentP
This commit is contained in:
2026-06-23 16:49:57 +08:00
parent 9a7522e928
commit 3c57941895
20 changed files with 734 additions and 127 deletions

View File

@@ -13,7 +13,7 @@ final class CreditLedgerBetFlowPresenter
public const DISPLAY_GAME_SETTLEMENT = 'game_settlement';
private const SETTLEMENT_REASONS = ['bet_hold_release', 'game_settlement_loss'];
private const SETTLEMENT_REASONS = ['bet_hold_release', 'game_settlement_loss', 'game_settlement_win'];
/**
* @param list<object> $rows credit_ledger 行(含 reason、ref_type、ref_id、amount、created_at
@@ -159,12 +159,17 @@ final class CreditLedgerBetFlowPresenter
*/
private function stakeMinorForSettlement(object $settlement, int $ticketId, array $ticketRefs): int
{
$fromLoss = abs((int) ($settlement->amount ?? 0));
if ($fromLoss > 0) {
return $fromLoss;
$fromTicketRef = (int) ($ticketRefs[$ticketId]['actual_deduct_amount'] ?? 0);
if ($fromTicketRef > 0) {
return $fromTicketRef;
}
return (int) ($ticketRefs[$ticketId]['actual_deduct_amount'] ?? 0);
$amount = (int) ($settlement->amount ?? 0);
if ($amount < 0) {
return abs($amount);
}
return 0;
}
/**
@@ -174,6 +179,7 @@ final class CreditLedgerBetFlowPresenter
private function mergeSettlementEntries(int $ticketId, array $entries, array $ticketRefs): ?object
{
$loss = null;
$win = null;
$release = null;
$latestAt = null;
@@ -181,6 +187,8 @@ final class CreditLedgerBetFlowPresenter
$reason = (string) ($entry->reason ?? '');
if ($reason === 'game_settlement_loss') {
$loss = $entry;
} elseif ($reason === 'game_settlement_win') {
$win = $entry;
} elseif ($reason === 'bet_hold_release') {
$release = $entry;
}
@@ -191,17 +199,17 @@ final class CreditLedgerBetFlowPresenter
}
}
$primary = $loss ?? $release;
$primary = $loss ?? $win ?? $release;
if ($primary === null) {
return null;
}
$signed = $loss !== null
? (int) $loss->amount
: 0;
: ($win !== null ? (int) $win->amount : 0);
return (object) [
'id' => (int) ($loss->id ?? $release->id ?? 0),
'id' => (int) ($loss->id ?? $win->id ?? $release->id ?? 0),
'amount' => $signed,
'reason' => self::DISPLAY_GAME_SETTLEMENT,
'ref_type' => 'ticket_item',