- 在多个控制器中引入 SettlementPartyEnrichment 服务,以优化代理结算和账单的处理逻辑。 - 更新 AgentSettlementBillIndexController 和 AgentSettlementBillShowController,支持根据账单 ID 和关键字进行查询。 - 在 AgentSettlementPeriodCloseController 中添加对站点管理权限的验证,确保只有具备相应权限的管理员能够关闭账期。 - 在 AgentSettlementPeriodIndexController 中更新账期数据的返回格式,提升数据的完整性和可用性。 - 引入对相对占成比例的支持,增强代理资料的管理能力,确保数据一致性。
114 lines
3.8 KiB
PHP
114 lines
3.8 KiB
PHP
<?php
|
||
|
||
namespace App\Services\AgentSettlement;
|
||
|
||
use App\Models\Player;
|
||
use App\Services\Player\PlayerCreditService;
|
||
use Illuminate\Support\Facades\DB;
|
||
|
||
final class SettlementPaymentService
|
||
{
|
||
public function __construct(
|
||
private readonly AgentSettlementBillGuard $billGuard,
|
||
private readonly PlayerCreditService $playerCreditService,
|
||
private readonly PeriodCloseRebateService $periodCloseRebate,
|
||
private readonly AgentSettlementPeriodCompletionService $periodCompletion,
|
||
) {}
|
||
|
||
public function confirmBill(int $billId): void
|
||
{
|
||
$this->billGuard->markConfirmed($billId);
|
||
}
|
||
|
||
/**
|
||
* @param array{method?: string|null, proof?: string|null, remark?: string|null} $meta
|
||
*/
|
||
public function recordPayment(int $billId, int $amount, int $adminUserId, array $meta = []): void
|
||
{
|
||
$bill = DB::table('settlement_bills')->where('id', $billId)->first();
|
||
if ($bill === null) {
|
||
throw new \InvalidArgumentException('bill_not_found');
|
||
}
|
||
|
||
$this->billGuard->assertPeriodMutable($billId);
|
||
$this->billGuard->assertPayable($billId);
|
||
|
||
$amount = min($amount, abs((int) $bill->unpaid_amount));
|
||
if ($amount <= 0) {
|
||
return;
|
||
}
|
||
|
||
[$payerType, $payerId, $payeeType, $payeeId] = $this->resolvePayerPayee($bill);
|
||
|
||
DB::table('payment_records')->insert([
|
||
'settlement_bill_id' => $billId,
|
||
'payer_type' => $payerType,
|
||
'payer_id' => $payerId,
|
||
'payee_type' => $payeeType,
|
||
'payee_id' => $payeeId,
|
||
'amount' => $amount,
|
||
'method' => $meta['method'] ?? null,
|
||
'proof' => $meta['proof'] ?? null,
|
||
'remark' => $meta['remark'] ?? null,
|
||
'status' => 'confirmed',
|
||
'created_by' => $adminUserId,
|
||
'confirmed_by' => $adminUserId,
|
||
'confirmed_at' => now(),
|
||
'created_at' => now(),
|
||
'updated_at' => now(),
|
||
]);
|
||
|
||
$newPaid = (int) $bill->paid_amount + $amount;
|
||
$newUnpaid = max(0, (int) $bill->unpaid_amount - $amount);
|
||
$status = $newUnpaid === 0 ? 'settled' : 'partial_paid';
|
||
|
||
DB::table('settlement_bills')->where('id', $billId)->update([
|
||
'paid_amount' => $newPaid,
|
||
'unpaid_amount' => $newUnpaid,
|
||
'status' => $status,
|
||
'updated_at' => now(),
|
||
]);
|
||
|
||
if ($bill->owner_type === 'player' && (int) $bill->owner_id > 0) {
|
||
$player = Player::query()->find((int) $bill->owner_id);
|
||
if ($player !== null) {
|
||
if ((int) $bill->net_amount > 0) {
|
||
$this->playerCreditService->releaseFromSettlement($player, $amount, $billId);
|
||
} elseif ((int) $bill->net_amount < 0) {
|
||
$this->playerCreditService->applySettlementPayout($player, $amount, $billId);
|
||
}
|
||
|
||
if ($status === 'settled') {
|
||
$this->periodCloseRebate->markRebatesSettledForBill($billId);
|
||
}
|
||
}
|
||
}
|
||
|
||
$this->periodCompletion->syncIfReady((int) $bill->settlement_period_id);
|
||
}
|
||
|
||
/**
|
||
* net_amount > 0:owner 应付 counterparty;< 0:counterparty 应付 owner。
|
||
*
|
||
* @return array{0: string, 1: int, 2: string, 3: int}
|
||
*/
|
||
private function resolvePayerPayee(object $bill): array
|
||
{
|
||
if ((int) $bill->net_amount < 0) {
|
||
return [
|
||
(string) $bill->counterparty_type,
|
||
(int) $bill->counterparty_id,
|
||
(string) $bill->owner_type,
|
||
(int) $bill->owner_id,
|
||
];
|
||
}
|
||
|
||
return [
|
||
(string) $bill->owner_type,
|
||
(int) $bill->owner_id,
|
||
(string) $bill->counterparty_type,
|
||
(int) $bill->counterparty_id,
|
||
];
|
||
}
|
||
}
|