Files
clinicpro/src/Payment/Gateway/GatewayFactory.php
T
hamed 1b171a82f4 feat(payment): add refund and reversal functionality to payment gateways
- Implemented `refund` and `reverse` methods in `PaymentGatewayInterface`.
- Added `PaymentRefundResult` class to handle refund operation results.
- Enhanced `MockGateway` and `SepGateway` to support refund and reversal operations.
- Updated `PaymentManager` to include `refundPayment` and `reversePayment` methods for handling refunds and reversals in transactions.
- Modified `ClinicSubscriptionRepository` and `SubscriptionService` to manage subscriptions during refunds.
- Added admin API endpoints for processing refunds and reversals.
- Updated security headers to allow form actions to the sandbox environment.
- Documented the new refund and reversal features in the API documentation.
2026-07-02 18:45:34 +03:30

98 lines
3.4 KiB
PHP

<?php
namespace App\Payment\Gateway;
use App\Config\Repository\SiteConfigRepository;
/**
* انتخاب/ساخت درگاه پرداخت (Factory + Strategy).
*
* تمام منطقِ «کدام درگاه، فعال است یا نه، حالت تست» اینجا متمرکز است تا کنترلر
* فقط Orchestration کند. افزودن درگاه جدید = ثبت آن به‌عنوان سرویس و اضافه‌کردن
* یک case در map + یک برچسب، بدون تغییر کنترلر.
*/
class GatewayFactory
{
/** @var array<string, PaymentGatewayInterface> */
private array $gateways;
/** @var array<string, string> برچسب فارسی هر درگاه */
private const LABELS = [
'mellat' => 'بانک ملت',
'sep' => 'سپ (سامان کیش)',
];
public function __construct(
MellatGateway $mellat,
SepGateway $sep,
private readonly MockGateway $mock,
private readonly SiteConfigRepository $configRepo,
) {
$this->gateways = [
$mellat->getName() => $mellat,
$sep->getName() => $sep,
];
}
public function isTestMode(): bool
{
return $this->configRepo->get('payment_test_mode') === '1';
}
/** حالت sandbox ملت (banktest.ir) — اتصال واقعی، جدا از test_mode/Mock. موقت. */
public function isMellatSandbox(): bool
{
return $this->configRepo->get('mellat_sandbox') === '1';
}
/**
* درگاهِ قابل‌استفاده برای این نام؛ در حالت تست همیشه Mock، در غیر این‌صورت
* درگاه واقعی در صورت فعال بودن. null یعنی نامعتبر/غیرفعال.
*/
public function resolve(string $name): ?PaymentGatewayInterface
{
// sandbox ملت: اتصال واقعی به banktest، نه Mock.
if ($name === 'mellat' && $this->isMellatSandbox()) {
return $this->gateways['mellat'] ?? null;
}
if ($this->isTestMode()) {
return $this->mock;
}
if (!$this->isEnabled($name)) {
return null;
}
return $this->gateways[$name] ?? null;
}
/** آیا درگاه در تنظیمات فعال است؟ کلید تنظیم‌نشده = فعال (سازگاری با نصب‌های قبلی). */
public function isEnabled(string $name): bool
{
$v = $this->configRepo->get($name . '_enabled');
return $v === null || $v === '1';
}
/**
* درگاه‌های قابل‌انتخاب برای نمایش به کاربر: در حالت تست فقط درگاه آزمایشی،
* در غیر این‌صورت هر درگاهی که اعتبارنامه‌اش ست شده و فعال است.
*
* @return array<int, array{name: string, label: string}>
*/
public function activeGateways(): array
{
if ($this->isMellatSandbox()) {
return [['name' => 'mellat', 'label' => 'بانک ملت (Sandbox)']];
}
if ($this->isTestMode()) {
return [['name' => 'mellat', 'label' => 'بانک ملت (آزمایشی)']];
}
$out = [];
foreach ($this->gateways as $name => $gateway) {
if ($gateway->isConfigured() && $this->isEnabled($name)) {
$out[] = ['name' => $name, 'label' => self::LABELS[$name] ?? $name];
}
}
return $out;
}
}