| @@ -4,8 +4,9 @@ | ||
| 4 | 4 | |
| 5 | 5 | use FluentCart\Api\StoreSettings; |
| 6 | 6 | use FluentCart\App\Helpers\Helper; |
| 7 | 7 | use FluentCart\App\Helpers\Status; |
| 8 | +use FluentCart\App\Models\OrderTransaction; | |
| 8 | 9 | use FluentCart\App\Modules\PaymentMethods\Core\GatewayManager; |
| 9 | 10 | use FluentCart\App\Services\URL; |
| 10 | 11 | use FluentCart\Framework\Support\Arr; |
| 11 | 12 | |
| @@ -19,18 +20,34 @@ | ||
| 19 | 20 | } |
| 20 | 21 | |
| 21 | 22 | public function listenerUrl($args = []) |
| 22 | 23 | { |
| 23 | - $listener = '/?fct_payment_listener=1&method=' . $this->slug; | |
| 24 | - $data = apply_filters_deprecated('fluent_cart_ipn_url_' . $this->slug, [ | |
| 25 | - ['listener_url' => site_url($listener)] | |
| 26 | - ], '1.3.16', 'fluent_cart/ipn_url_' . $this->slug, 'Use fluent_cart/ipn_url_' . $this->slug . ' instead of fluent_cart_ipn_url_' . $this->slug . '. It will be removed in v1.4.3.'); | |
| 24 | + // Must match the WebRoutes dispatch contract: it reads $_REQUEST['fluent-cart'] | |
| 25 | + // as the routed page and fires do_action('fluent_cart_action_' . $page), and | |
| 26 | + // GlobalPaymentHandler listens on 'fluent_cart_action_fct_payment_listener_ipn'. | |
| 27 | + $listener = '/?fluent-cart=fct_payment_listener_ipn&method=' . $this->slug; | |
| 28 | + $data = ['listener_url' => site_url($listener)]; | |
| 27 | 29 | |
| 28 | 30 | return apply_filters('fluent_cart/ipn_url_' . $this->slug, $data); |
| 29 | 31 | } |
| 30 | 32 | |
| 31 | - public function successUrl($uuid, $args = null) | |
| 33 | + /** | |
| 34 | + * Build the filterable post-payment success URL. | |
| 35 | + * | |
| 36 | + * @param OrderTransaction|string $transaction Transaction model or its uuid | |
| 37 | + * @param array|null $args Extra query args merged into the URL | |
| 38 | + * @return string | |
| 39 | + */ | |
| 40 | + public function successUrl($transaction, $args = null) | |
| 32 | 41 | { |
| 42 | + if ($transaction instanceof OrderTransaction) { | |
| 43 | + $transactionModel = $transaction; | |
| 44 | + $uuid = $transaction->uuid; | |
| 45 | + } else { | |
| 46 | + $uuid = (string)$transaction; | |
| 47 | + $transactionModel = OrderTransaction::query()->where('uuid', $uuid)->first(); | |
| 48 | + } | |
| 49 | + | |
| 33 | 50 | $queryArgs = array_merge( |
| 34 | 51 | array( |
| 35 | 52 | 'method' => $this->slug, |
| 36 | 53 | 'trx_hash' => $uuid, |
| @@ -47,13 +64,13 @@ | ||
| 47 | 64 | |
| 48 | 65 | $context = [ |
| 49 | 66 | 'transaction_hash' => $uuid, |
| 50 | 67 | 'args' => $args, |
| 51 | - 'payment_method' => $this->slug ?? '' | |
| 68 | + 'payment_method' => $this->slug ?? '', | |
| 69 | + 'transaction' => $transactionModel, | |
| 70 | + 'order' => $transactionModel ? $transactionModel->order : null | |
| 52 | 71 | ]; |
| 53 | - $url = apply_filters_deprecated('fluentcart/payment/success_url', [add_query_arg($queryArgs, $receiptUrl), $context], '1.3.16', 'fluent_cart/payment/success_url', 'Use fluent_cart/payment/success_url instead of fluentcart/payment/success_url. It will be removed in v1.4.3.'); | |
| 54 | - | |
| 55 | - return apply_filters('fluent_cart/payment/success_url', $url, $context); | |
| 72 | + return apply_filters('fluent_cart/payment/success_url', add_query_arg($queryArgs, $receiptUrl), $context); | |
| 56 | 73 | } |
| 57 | 74 | |
| 58 | 75 | public static function getCustomPaymentLink($orderHash): string |
| 59 | 76 | { |
| @@ -248,14 +265,20 @@ | ||
| 248 | 265 | return $billingInfo; |
| 249 | 266 | } |
| 250 | 267 | |
| 251 | 268 | |
| 269 | + /** | |
| 270 | + * Days in one billing cycle. Returns 0 when the interval cannot be resolved — | |
| 271 | + * neither a core interval nor one a fluent_cart/subscription_interval_in_days | |
| 272 | + * callback resolved to a positive day count. Callers must treat < 1 as | |
| 273 | + * unresolvable, never as a one-day cycle. | |
| 274 | + */ | |
| 252 | 275 | public static function getIntervalDays($interval = ''): int |
| 253 | 276 | { |
| 254 | 277 | if ($interval === 'yearly') { |
| 255 | 278 | $days = 365; |
| 256 | 279 | } elseif ($interval === 'monthly') { |
| 257 | - $days = 30; | |
| 280 | + $days = (int) gmdate('t'); // exact days in current month (handles leap year) to avoid false remaining days calculation | |
| 258 | 281 | } elseif ($interval === 'weekly') { |
| 259 | 282 | $days = 7; |
| 260 | 283 | } elseif ($interval === 'quarterly') { |
| 261 | 284 | $days = 90; |
| @@ -260,14 +283,18 @@ | ||
| 260 | 283 | } elseif ($interval === 'quarterly') { |
| 261 | 284 | $days = 90; |
| 262 | 285 | } elseif ($interval === 'half_yearly') { |
| 263 | 286 | $days = 182; |
| 287 | + } elseif ($interval === 'daily') { | |
| 288 | + $days = 1; | |
| 264 | 289 | } else { |
| 265 | - $days = 1; | |
| 290 | + $days = 0; | |
| 266 | 291 | } |
| 267 | 292 | |
| 268 | - return apply_filters('fluent_cart/subscription_interval_in_days', $days, [ | |
| 293 | + $days = (int) apply_filters('fluent_cart/subscription_interval_in_days', $days, [ | |
| 269 | 294 | 'interval' => $interval |
| 270 | 295 | ]); |
| 296 | + | |
| 297 | + return $days > 0 ? $days : 0; | |
| 271 | 298 | } |
| 272 | 299 | |
| 273 | 300 | } |