PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.16
Yatra – Travel Booking & Tour Operator Software v3.0.16
3.0.16 3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 All 84 releases
yatra / app / PaymentGateways / PaymentGatewayRegistry.php

PaymentGatewayRegistry.php in Yatra – Travel Booking & Tour Operator Software 3.0.16, at app/PaymentGateways/PaymentGatewayRegistry.php

418 lines 14.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace Yatra\PaymentGateways;
6
7 /**
8 * Payment Gateway Registry
9 * Manages registration and retrieval of payment gateways
10 */
11 class PaymentGatewayRegistry
12 {
13 private static ?PaymentGatewayRegistry $instance = null;
14 private array $gateways = [];
15
16 private function __construct()
17 {
18 // Register built-in gateways
19 $this->registerBuiltInGateways();
20
21 // Allow third-party plugins to register their gateways
22 do_action('yatra_register_payment_gateways', $this);
23 }
24
25 public static function getInstance(): self
26 {
27 if (self::$instance === null) {
28 self::$instance = new self();
29 }
30 return self::$instance;
31 }
32
33 /**
34 * Register built-in payment gateways (Free version)
35 * Only PayLater and PayPal are included in free version
36 * Premium gateways are registered by Yatra Pro via 'yatra_register_payment_gateways' hook
37 */
38 private function registerBuiltInGateways(): void
39 {
40 // Free gateways - always available
41 $freeGateways = [
42 Gateways\PayLater\PayLaterGateway::class, // Book Now Pay Later - Free
43 Gateways\PayPal\PayPalGateway::class, // PayPal - Free
44 ];
45
46 foreach ($freeGateways as $gatewayClass) {
47 if (class_exists($gatewayClass)) {
48 $this->register(new $gatewayClass());
49 }
50 }
51
52 // Premium gateways are registered by Yatra Pro plugin
53 // via the 'yatra_register_payment_gateways' action hook
54 }
55
56 /**
57 * Register a payment gateway
58 */
59 public function register(PaymentGatewayInterface $gateway): void
60 {
61 $this->gateways[$gateway->getId()] = $gateway;
62 }
63
64 /**
65 * Get a specific gateway by ID
66 */
67 public function get(string $id): ?PaymentGatewayInterface
68 {
69 return $this->gateways[$id] ?? null;
70 }
71
72 /**
73 * Get all registered gateways
74 */
75 public function getAll(): array
76 {
77 return $this->gateways;
78 }
79
80 /**
81 * Get all enabled/available gateways
82 */
83 public function getAvailable(): array
84 {
85 return array_filter($this->gateways, fn($gateway) => $gateway->isAvailable());
86 }
87
88 /**
89 * Gateways enabled in settings (may still lack API keys). Used for checkout UI.
90 *
91 * @return array<string, PaymentGatewayInterface>
92 */
93 public function getEnabledGateways(): array
94 {
95 return array_filter($this->gateways, fn($gateway) => $gateway->isEnabled());
96 }
97
98 /**
99 * Get list of premium gateway IDs (requires Yatra Pro)
100 */
101 public function getPremiumGatewayIds(): array
102 {
103 return [
104 'stripe',
105 'razorpay',
106 'mollie',
107 'paystack',
108 'square',
109 'authorize_net',
110 'bank_transfer',
111 ];
112 }
113
114 /**
115 * Check if a gateway is premium (requires Pro)
116 */
117 public function isPremiumGateway(string $gatewayId): bool
118 {
119 return in_array($gatewayId, $this->getPremiumGatewayIds(), true);
120 }
121
122 /**
123 * Check if Yatra Pro is active
124 */
125 private function isProActive(): bool
126 {
127 return defined('YATRA_PRO_VERSION') && class_exists('YatraPro\Plugin');
128 }
129
130 /**
131 * Get gateway definitions for admin settings UI
132 * Shows all gateways (registered + premium placeholders) with Pro badges
133 */
134 public function getDefinitions(): array
135 {
136 $definitions = [];
137 $isProActive = $this->isProActive();
138
139 // Add registered gateways
140 foreach ($this->gateways as $id => $gateway) {
141 $config = $gateway->getConfig();
142 $isPremium = $this->isPremiumGateway($id);
143
144 $definitions[$id] = [
145 'id' => $id,
146 'title' => $gateway->getTitle(),
147 'description' => $gateway->getDescription(),
148 'icon' => $gateway->getIcon(),
149 'sandbox_url' => $gateway->getSandboxUrl(),
150 'is_offline' => $gateway->isOffline(),
151 'supports' => $gateway->getSupports(),
152 'fields' => $gateway->getConfigFields(),
153 'config' => $config,
154 'enabled' => !empty($config['enabled']),
155 'is_premium' => $isPremium,
156 'requires_pro' => $isPremium && !$isProActive,
157 ];
158 }
159
160 // Add premium gateway placeholders if Pro is not active
161 if (!$isProActive) {
162 $premiumPlaceholders = $this->getPremiumGatewayPlaceholders();
163 foreach ($premiumPlaceholders as $id => $placeholder) {
164 // Only add if not already registered
165 if (!isset($definitions[$id])) {
166 $definitions[$id] = $placeholder;
167 }
168 }
169 }
170
171 return $definitions;
172 }
173
174 /**
175 * Get premium gateway placeholders for UI when Pro is not active
176 */
177 private function getPremiumGatewayPlaceholders(): array
178 {
179 return [
180 'stripe' => [
181 'id' => 'stripe',
182 'title' => __('Stripe', 'yatra'),
183 'description' => __('Accept credit card payments via Stripe', 'yatra'),
184 'icon' => YATRA_PLUGIN_URL . 'assets/images/payment-gateways/stripe.svg',
185 'sandbox_url' => '',
186 'is_offline' => false,
187 'supports' => ['refunds', 'subscriptions'],
188 'fields' => [],
189 'config' => ['enabled' => false],
190 'enabled' => false,
191 'is_premium' => true,
192 'requires_pro' => true,
193 ],
194 'razorpay' => [
195 'id' => 'razorpay',
196 'title' => __('Razorpay', 'yatra'),
197 'description' => __('Accept payments via Razorpay (India)', 'yatra'),
198 'icon' => YATRA_PLUGIN_URL . 'assets/images/payment-gateways/razorpay.svg',
199 'sandbox_url' => '',
200 'is_offline' => false,
201 'supports' => ['refunds'],
202 'fields' => [],
203 'config' => ['enabled' => false],
204 'enabled' => false,
205 'is_premium' => true,
206 'requires_pro' => true,
207 ],
208 'mollie' => [
209 'id' => 'mollie',
210 'title' => __('Mollie', 'yatra'),
211 'description' => __('Accept payments via Mollie (Europe)', 'yatra'),
212 'icon' => YATRA_PLUGIN_URL . 'assets/images/payment-gateways/mollie.svg',
213 'sandbox_url' => '',
214 'is_offline' => false,
215 'supports' => ['refunds'],
216 'fields' => [],
217 'config' => ['enabled' => false],
218 'enabled' => false,
219 'is_premium' => true,
220 'requires_pro' => true,
221 ],
222 'paystack' => [
223 'id' => 'paystack',
224 'title' => __('Paystack', 'yatra'),
225 'description' => __('Accept payments via Paystack (Africa)', 'yatra'),
226 'icon' => YATRA_PLUGIN_URL . 'assets/images/payment-gateways/paystack.svg',
227 'sandbox_url' => '',
228 'is_offline' => false,
229 'supports' => ['refunds'],
230 'fields' => [],
231 'config' => ['enabled' => false],
232 'enabled' => false,
233 'is_premium' => true,
234 'requires_pro' => true,
235 ],
236 'square' => [
237 'id' => 'square',
238 'title' => __('Square', 'yatra'),
239 'description' => __('Accept payments via Square (US/Canada)', 'yatra'),
240 'icon' => YATRA_PLUGIN_URL . 'assets/images/payment-gateways/square.svg',
241 'sandbox_url' => '',
242 'is_offline' => false,
243 'supports' => ['refunds'],
244 'fields' => [],
245 'config' => ['enabled' => false],
246 'enabled' => false,
247 'is_premium' => true,
248 'requires_pro' => true,
249 ],
250 'authorize_net' => [
251 'id' => 'authorize_net',
252 'title' => __('Authorize.Net', 'yatra'),
253 'description' => __('Accept payments via Authorize.Net (US)', 'yatra'),
254 'icon' => YATRA_PLUGIN_URL . 'assets/images/payment-gateways/authorize-net.svg',
255 'sandbox_url' => '',
256 'is_offline' => false,
257 'supports' => ['refunds'],
258 'fields' => [],
259 'config' => ['enabled' => false],
260 'enabled' => false,
261 'is_premium' => true,
262 'requires_pro' => true,
263 ],
264 'bank_transfer' => [
265 'id' => 'bank_transfer',
266 'title' => __('Bank Transfer', 'yatra'),
267 'description' => __('Accept manual bank transfer payments', 'yatra'),
268 'icon' => YATRA_PLUGIN_URL . 'assets/images/payment-gateways/bank_transfer.svg',
269 'sandbox_url' => '',
270 'is_offline' => true,
271 'supports' => [],
272 'fields' => [],
273 'config' => ['enabled' => false],
274 'enabled' => false,
275 'is_premium' => true,
276 'requires_pro' => true,
277 ],
278 ];
279 }
280
281 /**
282 * The gateway's customer-facing title — the same label the checkout shows.
283 *
284 * Prefers the operator's stored title, but ONLY when they actually
285 * customized it: the gateway's default title is persisted into the config
286 * at install time, and using that stored English string would shadow the
287 * translatable getTitle(). A genuine custom value (operator free-text, not
288 * translatable) is honored as-is.
289 *
290 * Works for any registered gateway, enabled or not, so a document about a
291 * past payment still names the gateway correctly after it was switched
292 * off. Returns '' when the id belongs to no registered gateway (e.g. a Pro
293 * gateway while Pro is inactive) so callers can fall back to the raw id.
294 */
295 public function resolveGatewayTitle(string $gatewayId): string
296 {
297 $gateway = $this->get($gatewayId);
298 if (!$gateway) {
299 return '';
300 }
301
302 $config = $gateway->getConfig();
303 $storedTitle = isset($config['title']) ? (string) $config['title'] : '';
304
305 return ($storedTitle !== '' && $storedTitle !== $gateway->getDefaultTitle())
306 ? $storedTitle
307 : $gateway->getTitle();
308 }
309
310 /**
311 * Gateways to show on checkout: all enabled in settings.
312 * Configuration is validated when processing payment (see processPayment).
313 */
314 public function getForCheckout(): array
315 {
316 $checkoutGateways = [];
317
318 foreach ($this->getEnabledGateways() as $id => $gateway) {
319 $config = $gateway->getConfig();
320 // Prefer a stored title/description ONLY when the operator actually
321 // customized it. The gateway's default title/description gets
322 // persisted into the config at install time, and using that stored
323 // English string here shadowed the translatable getTitle()/
324 // getDescription() — so the checkout label never translated. When
325 // the stored value equals the gateway's built-in default, fall
326 // through to the translated getter; a genuine custom value (which
327 // is operator free-text, not translatable) is still honored.
328 $storedDescription = isset($config['description']) ? (string) $config['description'] : '';
329 $checkoutGateways[] = [
330 'id' => $id,
331 'title' => $this->resolveGatewayTitle($id),
332 'description' => ($storedDescription !== '' && $storedDescription !== $gateway->getDefaultDescription())
333 ? $storedDescription
334 : $gateway->getDescription(),
335 'icon' => !empty($config['icon']) ? $config['icon'] : $gateway->getIcon(),
336 'is_offline' => $gateway->isOffline(),
337 'supports' => $gateway->getSupports(),
338 'is_configured' => $gateway->isProperlyConfigured(),
339 ];
340 }
341
342 return $checkoutGateways;
343 }
344
345 /**
346 * Save gateway configuration
347 */
348 public function saveGatewayConfig(string $gatewayId, array $config): bool
349 {
350 $gateway = $this->get($gatewayId);
351 if (!$gateway) {
352 return false;
353 }
354 return $gateway->saveConfig($config);
355 }
356
357 /**
358 * Process payment through a gateway
359 */
360 public function processPayment(string $gatewayId, array $paymentData): array
361 {
362 $gateway = $this->get($gatewayId);
363
364 if (!$gateway) {
365 return [
366 'success' => false,
367 'error' => __('Payment gateway not found', 'yatra'),
368 ];
369 }
370
371 if (!$gateway->isEnabled()) {
372 return [
373 'success' => false,
374 'error' => __('Payment gateway is not available', 'yatra'),
375 ];
376 }
377
378 if (!$gateway->isProperlyConfigured()) {
379 return [
380 'success' => false,
381 'error' => GatewayUserMessages::gatewayNotConfigured($gateway),
382 'code' => 'gateway_not_configured',
383 ];
384 }
385
386 return $gateway->processPayment($paymentData);
387 }
388
389 /**
390 * Enqueue scripts for all available gateways
391 */
392 public function enqueueScripts(): void
393 {
394 foreach ($this->getAvailable() as $gateway) {
395 if (method_exists($gateway, 'enqueueScripts')) {
396 $gateway->enqueueScripts();
397 }
398 }
399 }
400
401 /**
402 * Get frontend data for all available gateways
403 */
404 public function getFrontendData(): array
405 {
406 $data = [];
407
408 foreach ($this->getAvailable() as $id => $gateway) {
409 if (method_exists($gateway, 'getFrontendData')) {
410 $data[$id] = $gateway->getFrontendData();
411 }
412 }
413
414 return $data;
415 }
416 }
417
418