| @@ -490,9 +490,11 @@ | ||
| 490 | 490 | |
| 491 | 491 | /** |
| 492 | 492 | * Determine the license status for payment fee decisions. |
| 493 | 493 | * |
| 494 | - * Mirrors the API's determine_status_from_license_details logic. | |
| 494 | + * Mirrors determine_status_from_license_details in the Stripe Connect service, | |
| 495 | + * including its 2016-04-26 grandfathered cutoff. Square and PayPal Commerce use a | |
| 496 | + * later cutoff, so read their fees through payment_fees_apply instead. | |
| 495 | 497 | * |
| 496 | 498 | * @since 6.31 |
| 497 | 499 | * |
| 498 | 500 | * @return string 'active', 'expired', or 'free'. |
| @@ -505,16 +507,16 @@ | ||
| 505 | 507 | } |
| 506 | 508 | |
| 507 | 509 | $error = $version_info['error'] ?? array(); |
| 508 | 510 | |
| 509 | - if ( is_array( $error ) ) { | |
| 510 | - $code = $error['code'] ?? ''; | |
| 511 | + if ( is_array( $error ) && 'expired' === ( $error['code'] ?? '' ) ) { | |
| 512 | + return 'expired'; | |
| 513 | + } | |
| 511 | 514 | |
| 512 | - if ( 'expired' === $code ) { | |
| 513 | - return 'expired'; | |
| 514 | - } | |
| 515 | + if ( self::is_grandfathered_license() ) { | |
| 516 | + $expires = self::get_grandfathered_expiration( $version_info ); | |
| 515 | 517 | |
| 516 | - if ( 'grandfathered' === $code && isset( $error['expires'] ) && gmdate( 'Y-m-d', $error['expires'] ) < '2016-04-26' ) { | |
| 518 | + if ( $expires && gmdate( 'Y-m-d', $expires ) < '2016-04-26' ) { | |
| 517 | 519 | return 'free'; |
| 518 | 520 | } |
| 519 | 521 | } |
| 520 | 522 | |
| @@ -522,8 +524,83 @@ | ||
| 522 | 524 | return 'active'; |
| 523 | 525 | } |
| 524 | 526 | |
| 525 | 527 | return 'free'; |
| 528 | + } | |
| 529 | + | |
| 530 | + /** | |
| 531 | + * Check if a connect service charges its per-transaction fee for this license. | |
| 532 | + * | |
| 533 | + * Square and PayPal Commerce launched long after lifetime licenses stopped being | |
| 534 | + * sold, so their services charge every grandfathered license. Stripe's predates | |
| 535 | + * them and exempts most of them, which get_payment_license_status mirrors. | |
| 536 | + * | |
| 537 | + * @since 6.34 | |
| 538 | + * | |
| 539 | + * @param string $service The connect service: 'stripe', 'square', or 'paypal'. | |
| 540 | + * | |
| 541 | + * @return bool | |
| 542 | + */ | |
| 543 | + public static function payment_fees_apply( $service ) { | |
| 544 | + if ( 'active' !== self::get_payment_license_status() ) { | |
| 545 | + return true; | |
| 546 | + } | |
| 547 | + | |
| 548 | + if ( in_array( $service, array( 'square', 'paypal' ), true ) ) { | |
| 549 | + return self::is_grandfathered_license(); | |
| 550 | + } | |
| 551 | + | |
| 552 | + return false; | |
| 553 | + } | |
| 554 | + | |
| 555 | + /** | |
| 556 | + * Check if the primary license is grandfathered. | |
| 557 | + * | |
| 558 | + * The API reports this on the Pro add-on itself, the same place | |
| 559 | + * FrmProAddonsController::license_type reads it from. Older responses put it | |
| 560 | + * in the top level error instead, so check both. | |
| 561 | + * | |
| 562 | + * @since 6.34 | |
| 563 | + * | |
| 564 | + * @return bool | |
| 565 | + */ | |
| 566 | + public static function is_grandfathered_license() { | |
| 567 | + $version_info = self::get_primary_license_info(); | |
| 568 | + | |
| 569 | + if ( ! $version_info ) { | |
| 570 | + return false; | |
| 571 | + } | |
| 572 | + | |
| 573 | + $error = $version_info['error'] ?? array(); | |
| 574 | + | |
| 575 | + if ( is_array( $error ) && 'grandfathered' === ( $error['code'] ?? '' ) ) { | |
| 576 | + return true; | |
| 577 | + } | |
| 578 | + | |
| 579 | + $pro = self::get_pro_from_addons( $version_info ); | |
| 580 | + | |
| 581 | + return 'grandfathered' === ( $pro['code'] ?? '' ); | |
| 582 | + } | |
| 583 | + | |
| 584 | + /** | |
| 585 | + * Get the expiration timestamp reported alongside a grandfathered license. | |
| 586 | + * | |
| 587 | + * @since 6.34 | |
| 588 | + * | |
| 589 | + * @param array $version_info The license info from get_primary_license_info. | |
| 590 | + * | |
| 591 | + * @return int | |
| 592 | + */ | |
| 593 | + private static function get_grandfathered_expiration( $version_info ) { | |
| 594 | + $error = $version_info['error'] ?? array(); | |
| 595 | + | |
| 596 | + if ( is_array( $error ) && ! empty( $error['expires'] ) ) { | |
| 597 | + return (int) $error['expires']; | |
| 598 | + } | |
| 599 | + | |
| 600 | + $pro = self::get_pro_from_addons( $version_info ); | |
| 601 | + | |
| 602 | + return (int) ( $pro['expires'] ?? 0 ); | |
| 526 | 603 | } |
| 527 | 604 | |
| 528 | 605 | /** |
| 529 | 606 | * @since 4.0.01 |