fix: 部分收付累计释额并扩展结算 E2E 与 CI
Some checks failed
lotterLaravel CI / test (push) Has been cancelled
lotterLaravel E2E / e2e-api (push) Has been cancelled

账期收付改为按累计已付同步 credit_ledger,修复多笔 partial_paid 与坏账核销重复释额;新增 API E2E(占成、权限、部分收付/坏账)与 GitHub Actions e2e-api job。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-22 09:48:01 +08:00
parent 6ec9634704
commit 3f29229499
23 changed files with 1251 additions and 111 deletions

View File

@@ -105,7 +105,8 @@ final class AgentSettlementBadDebtService
if ((string) $original->owner_type === 'player' && (int) $original->owner_id > 0 && (int) $original->net_amount > 0) {
$player = Player::query()->find((int) $original->owner_id);
if ($player !== null) {
$this->playerCreditService->releaseFromSettlement($player, $unpaid, $originalBillId);
$cumulativePaid = (int) $original->paid_amount + $unpaid;
$this->playerCreditService->releaseFromSettlement($player, $cumulativePaid, $originalBillId);
}
}

View File

@@ -86,9 +86,9 @@ final class SettlementPaymentService
$player = Player::query()->find((int) $bill->owner_id);
if ($player !== null) {
if ((int) $bill->net_amount > 0) {
$this->playerCreditService->releaseFromSettlement($player, $payAmount, $billId);
$this->playerCreditService->releaseFromSettlement($player, $newPaid, $billId);
} elseif ((int) $bill->net_amount < 0) {
$this->playerCreditService->applySettlementPayout($player, $payAmount, $billId);
$this->playerCreditService->applySettlementPayout($player, $newPaid, $billId);
}
if ($status === 'settled') {

View File

@@ -359,62 +359,89 @@ final class PlayerCreditService
]);
}
public function releaseFromSettlement(Player $player, int $amountMinor, int $billId): void
/**
* @param int $cumulativePaidMinor 账单累计已登记收付minor支持部分收付多笔递增。
*/
public function releaseFromSettlement(Player $player, int $cumulativePaidMinor, int $billId): void
{
if ($amountMinor <= 0 || ! PlayerFundingMode::usesCredit($player)) {
if ($cumulativePaidMinor <= 0 || ! PlayerFundingMode::usesCredit($player)) {
return;
}
// 幂等闸门credit_ledger (settlement_bill, settlement_confirm) 唯一;重复调用直接返回。
try {
DB::table('credit_ledger')->insert([
'owner_type' => 'player',
'owner_id' => $player->id,
'amount' => $amountMinor,
'reason' => 'settlement_confirm',
'ref_type' => 'settlement_bill',
'ref_id' => $billId,
'created_at' => now(),
'updated_at' => now(),
]);
} catch (QueryException $e) {
if ($this->isUniqueViolation($e)) {
return;
}
throw $e;
$delta = $this->syncSettlementBillLedger(
$player,
$billId,
'settlement_confirm',
$cumulativePaidMinor,
);
if ($delta > 0) {
$this->decreaseUsedCredit($player, $delta);
}
$this->decreaseUsedCredit($player, $amountMinor);
}
public function applySettlementPayout(Player $player, int $amountMinor, int $billId): void
/**
* @param int $cumulativePaidMinor 账单累计已登记收付minor支持部分收付多笔递增。
*/
public function applySettlementPayout(Player $player, int $cumulativePaidMinor, int $billId): void
{
if ($amountMinor <= 0) {
if ($cumulativePaidMinor <= 0 || ! PlayerFundingMode::usesCredit($player)) {
return;
}
if (! PlayerFundingMode::usesCredit($player)) {
return;
$this->syncSettlementBillLedger(
$player,
$billId,
'settlement_payout',
$cumulativePaidMinor,
);
}
/**
* 同步账期收付台账:每账单每种 reason 仅一行amount 为累计已付;返回本次应追加的 minor 增量。
*/
private function syncSettlementBillLedger(
Player $player,
int $billId,
string $reason,
int $cumulativeMinor,
): int {
$existing = DB::table('credit_ledger')
->where('owner_type', 'player')
->where('owner_id', $player->id)
->where('reason', $reason)
->where('ref_type', 'settlement_bill')
->where('ref_id', $billId)
->lockForUpdate()
->first();
$recorded = $existing !== null ? (int) $existing->amount : 0;
$delta = $cumulativeMinor - $recorded;
if ($delta <= 0) {
return 0;
}
// 幂等闸门credit_ledger (settlement_bill, settlement_payout) 唯一;重复入账直接返回。
try {
$now = now();
if ($existing === null) {
DB::table('credit_ledger')->insert([
'owner_type' => 'player',
'owner_id' => $player->id,
'amount' => $amountMinor,
'reason' => 'settlement_payout',
'amount' => $cumulativeMinor,
'reason' => $reason,
'ref_type' => 'settlement_bill',
'ref_id' => $billId,
'created_at' => now(),
'updated_at' => now(),
'created_at' => $now,
'updated_at' => $now,
]);
} catch (QueryException $e) {
if ($this->isUniqueViolation($e)) {
return;
}
throw $e;
} else {
DB::table('credit_ledger')
->where('id', (int) $existing->id)
->update([
'amount' => $cumulativeMinor,
'updated_at' => $now,
]);
}
return $delta;
}
private function decreaseUsedCredit(Player $player, int $amountMinor): void