update api register
This commit is contained in:
@@ -3,7 +3,9 @@
|
||||
namespace App\Services\Wallet;
|
||||
|
||||
use App\Models\Tenant;
|
||||
use App\Models\TenantPaymentSetting;
|
||||
use App\Models\User;
|
||||
use App\Models\VoucherAgent;
|
||||
use App\Models\Wallet;
|
||||
use App\Models\WalletLedgerEntry;
|
||||
use App\Models\WalletTransaction;
|
||||
@@ -15,14 +17,60 @@ use Illuminate\Validation\ValidationException;
|
||||
|
||||
class WalletService
|
||||
{
|
||||
public function chargeUser(User $user, int $tenantId, float $amount, string $idempotencyKey, string $description): WalletTransaction
|
||||
{
|
||||
return DB::transaction(function () use ($user, $tenantId, $amount, $idempotencyKey, $description) {
|
||||
$existing = WalletTransaction::where('idempotency_key', $idempotencyKey)->first();
|
||||
if ($existing) {
|
||||
return $existing;
|
||||
}
|
||||
|
||||
$wallet = Wallet::lockForUpdate()->find($this->walletFor($user, $tenantId, 'deposit')->id);
|
||||
if ((float) $wallet->available_balance < $amount) {
|
||||
throw ValidationException::withMessages(['wallet' => 'Saldo deposit agen pada tenant ini tidak mencukupi.']);
|
||||
}
|
||||
|
||||
$transaction = WalletTransaction::create([
|
||||
'uuid' => Str::uuid(), 'transaction_number' => 'WLT-'.now()->format('YmdHis').'-'.Str::upper(Str::random(6)),
|
||||
'type' => 'voucher_purchase', 'status' => 'processing', 'initiated_by' => $user->id,
|
||||
'amount' => $amount, 'fee' => 0, 'idempotency_key' => $idempotencyKey, 'description' => $description,
|
||||
]);
|
||||
$this->post($wallet, $transaction, 'debit', $amount);
|
||||
$transaction->update(['status' => 'completed', 'completed_at' => now()]);
|
||||
|
||||
return $transaction;
|
||||
});
|
||||
}
|
||||
|
||||
public function wallets(User $user, ?int $tenantId)
|
||||
{
|
||||
$wallets = collect([$this->walletFor($user, 'user')]);
|
||||
if ($tenantId && ($user->isMasterAdmin() || $user->isTenantOwner())) {
|
||||
$wallets->push($this->walletFor(Tenant::findOrFail($tenantId), 'tenant'));
|
||||
if (! $tenantId) {
|
||||
return collect();
|
||||
}
|
||||
|
||||
return $wallets->values();
|
||||
$balances = collect([$this->balanceData($this->walletFor($user, $tenantId, 'deposit'), 'deposit', 'Saldo Deposit')]);
|
||||
$usesGlobalGateway = TenantPaymentSetting::where('tenant_id', $tenantId)
|
||||
->where('payment_mode', 'platform_gateway')->whereNotNull('platform_gateway_account_id')->exists();
|
||||
if ($usesGlobalGateway && ($user->isMasterAdmin() || $user->isTenantOwner($tenantId))) {
|
||||
$balances->push($this->balanceData($this->walletFor(Tenant::findOrFail($tenantId), $tenantId, 'tenant_settlement'), 'tenant_settlement', 'Saldo Settlement Tenant'));
|
||||
}
|
||||
|
||||
$agent = VoucherAgent::where('tenant_id', $tenantId)->where('user_id', $user->id)
|
||||
->where('payment_type', 'postpaid')->where('status', 'active')->first();
|
||||
if ($agent) {
|
||||
$balances->push([
|
||||
'id' => "credit-{$agent->id}", 'uuid' => $agent->uuid, 'tenant_id' => $tenantId,
|
||||
'wallet_type' => 'voucher_credit', 'balance_kind' => 'credit', 'label' => 'Saldo Kredit Voucher',
|
||||
'credit_limit' => $agent->credit_limit, 'used_credit' => $agent->outstanding_balance,
|
||||
'remaining_credit' => number_format(max(0, (float) $agent->credit_limit - (float) $agent->outstanding_balance), 2, '.', ''),
|
||||
'available_balance' => number_format(max(0, (float) $agent->credit_limit - (float) $agent->outstanding_balance), 2, '.', ''),
|
||||
'pending_balance' => '0.00', 'locked_balance' => '0.00', 'currency' => 'IDR',
|
||||
'status' => $agent->status, 'ledger_available' => false, 'can_withdraw' => false, 'can_transfer' => false,
|
||||
'usage_note' => 'Khusus untuk pembelian voucher hotspot pada tenant ini.',
|
||||
]);
|
||||
}
|
||||
|
||||
return $balances->values();
|
||||
}
|
||||
|
||||
public function ledger(Wallet $wallet, User $actor, ?int $tenantId, array $filters)
|
||||
@@ -37,6 +85,9 @@ class WalletService
|
||||
{
|
||||
$this->authorizeWallet($source, $actor, $tenantId);
|
||||
$this->authorizeWallet($destination, $actor, $tenantId);
|
||||
if ((int) $source->tenant_id !== (int) $destination->tenant_id || (int) $source->tenant_id !== (int) $tenantId) {
|
||||
throw ValidationException::withMessages(['destination_wallet_id' => 'Saldo tidak dapat dipindahkan antar tenant.']);
|
||||
}
|
||||
if ($source->is($destination)) {
|
||||
throw ValidationException::withMessages(['destination_wallet_id' => 'Dompet tujuan harus berbeda.']);
|
||||
}
|
||||
@@ -63,6 +114,9 @@ class WalletService
|
||||
public function requestWithdrawal(Wallet $wallet, array $data, User $actor, ?int $tenantId): WalletWithdrawal
|
||||
{
|
||||
$this->authorizeWallet($wallet, $actor, $tenantId);
|
||||
if ($wallet->wallet_type !== 'tenant_settlement') {
|
||||
throw ValidationException::withMessages(['wallet' => 'Saldo deposit user hanya dapat digunakan untuk transaksi layanan dan tidak dapat ditarik tunai.']);
|
||||
}
|
||||
|
||||
return DB::transaction(function () use ($wallet, $data, $actor) {
|
||||
$locked = Wallet::lockForUpdate()->findOrFail($wallet->id);
|
||||
@@ -82,14 +136,25 @@ class WalletService
|
||||
});
|
||||
}
|
||||
|
||||
private function walletFor(Model $owner, string $type): Wallet
|
||||
private function walletFor(Model $owner, int $tenantId, string $type): Wallet
|
||||
{
|
||||
return Wallet::firstOrCreate(
|
||||
['owner_type' => $owner->getMorphClass(), 'owner_id' => $owner->getKey(), 'wallet_type' => $type, 'currency' => 'IDR'],
|
||||
['owner_type' => $owner->getMorphClass(), 'owner_id' => $owner->getKey(), 'tenant_id' => $tenantId, 'wallet_type' => $type, 'currency' => 'IDR'],
|
||||
['uuid' => Str::uuid(), 'status' => 'active']
|
||||
);
|
||||
}
|
||||
|
||||
private function balanceData(Wallet $wallet, string $kind, string $label): array
|
||||
{
|
||||
return [
|
||||
...$wallet->toArray(), 'balance_kind' => $kind, 'label' => $label, 'ledger_available' => true,
|
||||
'can_withdraw' => $kind === 'tenant_settlement', 'can_transfer' => false,
|
||||
'usage_note' => $kind === 'deposit'
|
||||
? 'Dapat digunakan untuk transaksi layanan pada tenant ini.'
|
||||
: 'Dana tenant dari transaksi melalui payment gateway global.',
|
||||
];
|
||||
}
|
||||
|
||||
private function newTransaction(string $type, float $amount, User $actor, string $description, float $fee = 0): WalletTransaction
|
||||
{
|
||||
return WalletTransaction::create([
|
||||
@@ -116,8 +181,9 @@ class WalletService
|
||||
if ($actor->isMasterAdmin()) {
|
||||
return;
|
||||
}
|
||||
$allowed = ($wallet->owner_type === $actor->getMorphClass() && (int) $wallet->owner_id === (int) $actor->id)
|
||||
|| ($actor->isTenantOwner() && $wallet->owner_type === (new Tenant)->getMorphClass() && (int) $wallet->owner_id === (int) $tenantId);
|
||||
abort_unless($allowed, 403, 'Dompet tidak dapat diakses.');
|
||||
$sameTenant = $tenantId && (int) $wallet->tenant_id === (int) $tenantId;
|
||||
$allowed = $sameTenant && (($wallet->owner_type === $actor->getMorphClass() && (int) $wallet->owner_id === (int) $actor->id)
|
||||
|| ($actor->isTenantOwner($tenantId) && $wallet->owner_type === (new Tenant)->getMorphClass() && (int) $wallet->owner_id === (int) $tenantId));
|
||||
abort_unless($allowed, 403, 'Saldo tidak dapat diakses.');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user