139 lines
7.1 KiB
PHP
139 lines
7.1 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Payment;
|
|
|
|
use App\Models\PaymentGatewayAccount;
|
|
use App\Models\PaymentProvider;
|
|
use App\Models\PaymentTransaction;
|
|
use App\Models\TenantPaymentSetting;
|
|
use App\Models\User;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
class PaymentGatewayService
|
|
{
|
|
public function providers()
|
|
{
|
|
return PaymentProvider::where('enabled', true)->orderBy('name')->get();
|
|
}
|
|
|
|
public function settings(User $actor, ?int $tenantId): array
|
|
{
|
|
$accounts = PaymentGatewayAccount::with('provider:id,code,name,scope,capabilities,credential_schema')
|
|
->when(! $actor->isMasterAdmin(), fn ($q) => $q->where(fn ($x) => $x->where('tenant_id', $tenantId)->orWhere('scope', 'platform')))
|
|
->when($actor->isMasterAdmin() && $tenantId, fn ($q) => $q->where(fn ($x) => $x->where('tenant_id', $tenantId)->orWhere('scope', 'platform')))
|
|
->orderBy('scope')->orderBy('name')->get()
|
|
->map(fn ($account) => $this->maskedAccount($account));
|
|
|
|
$setting = $tenantId ? TenantPaymentSetting::with(['tenantGateway.provider', 'platformGateway.provider'])->firstOrCreate(
|
|
['tenant_id' => $tenantId],
|
|
['payment_mode' => 'disabled', 'fee_bearer' => 'customer', 'default_expiry_minutes' => 1440]
|
|
) : null;
|
|
|
|
return compact('accounts', 'setting');
|
|
}
|
|
|
|
public function saveAccount(array $data, User $actor, ?int $tenantId, ?PaymentGatewayAccount $account = null): PaymentGatewayAccount
|
|
{
|
|
$scope = $data['scope'];
|
|
if ($scope === 'platform' && ! $actor->isMasterAdmin()) {
|
|
abort(403, 'Hanya Master Admin yang dapat mengelola gateway platform.');
|
|
}
|
|
$effectiveTenant = $scope === 'platform' ? null : ($actor->isMasterAdmin() ? ($data['tenant_id'] ?? $tenantId) : $tenantId);
|
|
if ($scope === 'tenant' && ! $effectiveTenant) {
|
|
throw ValidationException::withMessages(['tenant_id' => 'Tenant wajib dipilih.']);
|
|
}
|
|
if ($account && ($account->scope !== $scope || ($scope === 'tenant' && (int) $account->tenant_id !== (int) $effectiveTenant))) {
|
|
abort(403);
|
|
}
|
|
|
|
return DB::transaction(function () use ($data, $account, $scope, $effectiveTenant) {
|
|
if (($data['enabled'] ?? false) && $scope === 'tenant') {
|
|
PaymentGatewayAccount::where('tenant_id', $effectiveTenant)->where('scope', 'tenant')
|
|
->when($account, fn ($q) => $q->whereKeyNot($account->id))->update(['enabled' => false, 'is_default' => false]);
|
|
}
|
|
if (($data['is_default'] ?? false) && $scope === 'platform') {
|
|
PaymentGatewayAccount::where('scope', 'platform')
|
|
->when($account, fn ($q) => $q->whereKeyNot($account->id))->update(['is_default' => false]);
|
|
}
|
|
|
|
$payload = [
|
|
'uuid' => $account?->uuid ?? Str::uuid(),
|
|
'payment_provider_id' => $data['payment_provider_id'],
|
|
'tenant_id' => $effectiveTenant,
|
|
'scope' => $scope,
|
|
'name' => $data['name'],
|
|
'environment' => $data['environment'],
|
|
'settings' => $data['settings'] ?? [],
|
|
'enabled' => $data['enabled'] ?? false,
|
|
'is_default' => $data['is_default'] ?? false,
|
|
];
|
|
if (! empty($data['credentials'])) {
|
|
$payload['credentials'] = $data['credentials'];
|
|
}
|
|
if (filled($data['webhook_secret'] ?? null)) {
|
|
$payload['webhook_secret'] = $data['webhook_secret'];
|
|
}
|
|
|
|
$model = $account ?: new PaymentGatewayAccount;
|
|
$model->fill($payload)->save();
|
|
|
|
return $model->load('provider');
|
|
});
|
|
}
|
|
|
|
public function saveTenantSetting(array $data, User $actor, ?int $tenantId): TenantPaymentSetting
|
|
{
|
|
$effectiveTenant = $actor->isMasterAdmin() ? ($data['tenant_id'] ?? $tenantId) : $tenantId;
|
|
if (! $effectiveTenant) {
|
|
throw ValidationException::withMessages(['tenant_id' => 'Tenant wajib dipilih.']);
|
|
}
|
|
|
|
if ($data['payment_mode'] === 'tenant_gateway') {
|
|
$valid = PaymentGatewayAccount::whereKey($data['tenant_gateway_account_id'] ?? 0)
|
|
->where('tenant_id', $effectiveTenant)->where('scope', 'tenant')->where('enabled', true)->exists();
|
|
if (! $valid) {
|
|
throw ValidationException::withMessages(['tenant_gateway_account_id' => 'Gateway tenant aktif tidak valid.']);
|
|
}
|
|
}
|
|
if ($data['payment_mode'] === 'platform_gateway') {
|
|
$valid = PaymentGatewayAccount::whereKey($data['platform_gateway_account_id'] ?? 0)
|
|
->whereNull('tenant_id')->where('scope', 'platform')->where('enabled', true)->exists();
|
|
if (! $valid) {
|
|
throw ValidationException::withMessages(['platform_gateway_account_id' => 'Gateway platform aktif tidak valid.']);
|
|
}
|
|
}
|
|
|
|
return TenantPaymentSetting::updateOrCreate(['tenant_id' => $effectiveTenant], [
|
|
...$data,
|
|
'tenant_id' => $effectiveTenant,
|
|
'tenant_gateway_account_id' => $data['payment_mode'] === 'tenant_gateway' ? $data['tenant_gateway_account_id'] : null,
|
|
'platform_gateway_account_id' => $data['payment_mode'] === 'platform_gateway' ? $data['platform_gateway_account_id'] : null,
|
|
])->load(['tenantGateway.provider', 'platformGateway.provider']);
|
|
}
|
|
|
|
public function transactions(array $filters, User $actor, ?int $tenantId)
|
|
{
|
|
return PaymentTransaction::with(['tenant:id,tenant_name', 'user:id,name', 'customer:id,name,customer_code', 'invoice:id,invoice_number', 'account.provider:id,code,name'])
|
|
->when(! $actor->isMasterAdmin(), fn ($q) => $q->where('tenant_id', $tenantId))
|
|
->when($actor->isMasterAdmin() && $tenantId, fn ($q) => $q->where('tenant_id', $tenantId))
|
|
->when($filters['search'] ?? null, fn ($q, $search) => $q->where(fn ($x) => $x->where('transaction_number', 'ilike', "%{$search}%")->orWhere('provider_reference', 'ilike', "%{$search}%")))
|
|
->when($filters['status'] ?? null, fn ($q, $value) => $q->where('status', $value))
|
|
->when($filters['provider_code'] ?? null, fn ($q, $value) => $q->where('provider_code', $value))
|
|
->when($filters['purpose'] ?? null, fn ($q, $value) => $q->where('purpose', $value))
|
|
->when($filters['date_from'] ?? null, fn ($q, $value) => $q->whereDate('created_at', '>=', $value))
|
|
->when($filters['date_to'] ?? null, fn ($q, $value) => $q->whereDate('created_at', '<=', $value))
|
|
->orderBy($filters['sort_by'] ?? 'id', $filters['sort_direction'] ?? 'desc')
|
|
->paginate($filters['per_page'] ?? 10);
|
|
}
|
|
|
|
private function maskedAccount(PaymentGatewayAccount $account): PaymentGatewayAccount
|
|
{
|
|
$account->setAttribute('has_credentials', ! empty($account->getRawOriginal('credentials')));
|
|
$account->setAttribute('has_webhook_secret', ! empty($account->getRawOriginal('webhook_secret')));
|
|
|
|
return $account;
|
|
}
|
|
}
|