Skip to content
Snippets Groups Projects
Webhook.php 5.55 KiB
Newer Older
  • Learn to ignore specific revisions
  • mattwire's avatar
    mattwire committed
    <?php
    
    use CRM_Stripe_ExtensionUtil as E;
    
    class CRM_Stripe_Webhook {
    
    
    mattwire's avatar
    mattwire committed
      use CRM_Stripe_WebhookTrait;
    
    mattwire's avatar
    mattwire committed
    
      /**
    
       * Checks whether the payment processors have a correctly configured webhook
    
    mattwire's avatar
    mattwire committed
       *
       * @see stripe_civicrm_check()
    
       * @param bool $attemptFix If TRUE, try to fix the webhook.
    
    mattwire's avatar
    mattwire committed
       */
    
      public static function check(&$messages, $attemptFix = FALSE) {
    
    mattwire's avatar
    mattwire committed
        $result = civicrm_api3('PaymentProcessor', 'get', [
          'class_name' => 'Payment_Stripe',
          'is_active' => 1,
    
    mattwire's avatar
    mattwire committed
        ]);
    
        foreach ($result['values'] as $paymentProcessor) {
    
    mattwire's avatar
    mattwire committed
          $webhook_path = self::getWebhookPath($paymentProcessor['id']);
    
    mattwire's avatar
    mattwire committed
    
    
          $processor = new CRM_Core_Payment_Stripe('', civicrm_api3('PaymentProcessor', 'getsingle', ['id' => $paymentProcessor['id']]));
          $processor->setAPIParams();
    
    
    mattwire's avatar
    mattwire committed
          try {
            $webhooks = \Stripe\WebhookEndpoint::all(["limit" => 100]);
          }
          catch (Exception $e) {
            $error = $e->getMessage();
            $messages[] = new CRM_Utils_Check_Message(
              'stripe_webhook',
    
    mattwire's avatar
    mattwire committed
              \Psr\Log\LogLevel::ERROR,
              'fa-money'
            );
    
            continue;
          }
    
          $found_wh = FALSE;
          foreach ($webhooks->data as $wh) {
            if ($wh->url == $webhook_path) {
              $found_wh = TRUE;
              // Check and update webhook
    
                $updates = self::checkWebhook($wh);
                if ($updates) {
                  if ($attemptFix) {
                    // We should try to update the webhook.
                    $messageTexts[] = E::ts('Unable to update the webhook %1. To correct this please delete the webhook at Stripe and then revisit this page which will recreate it correctly.',
                      [1 => urldecode($webhook_path)]
                    );
                    \Stripe\WebhookEndpoint::update($wh['id'], $updates);
                  }
                  else {
                    $messageTexts[] = E::ts('Problems detected with Stripe webhook %1. Please visit <a href="%2">Fix Stripe Webhook</a> to fix.', [
                      1 => urldecode($webhook_path),
                      2 => CRM_Utils_System::url('civicrm/stripe/fix-webhook'),
                    ]);
                  }
                }
    
                $messageTexts[] = E::ts('Could not check/update existing webhooks, got error from stripe <em>%1</em>', [
                    1 => htmlspecialchars($e->getMessage())
                  ]
    
    mattwire's avatar
    mattwire committed
            }
          }
    
          if (!$found_wh) {
    
            if ($attemptFix) {
              try {
                // Try to create one.
                self::createWebhook($paymentProcessor['id']);
              }
              catch (Exception $e) {
                $messageTexts[] = E::ts('Could not create webhook, got error from stripe <em>%1</em>', [
                  1 => htmlspecialchars($e->getMessage())
                ]);
              }
    
    mattwire's avatar
    mattwire committed
            }
    
              $messageTexts[] = E::ts('Stripe Webhook missing! Please visit <a href="%1">Fix Stripe Webhook</a> to fix.<br />Expected webhook path is: <a href="%2" target="_blank">%2</a>',
                [
                  1 => CRM_Utils_System::url('civicrm/stripe/fix-webhook'),
                  2 => $webhook_path,
                ]
              );
    
    mattwire's avatar
    mattwire committed
            }
          }
    
    
          foreach ($messageTexts as $messageText) {
            $messages[] = new CRM_Utils_Check_Message(
              'stripe_webhook',
              $messageText,
    
      /**
       * Get the error message title for the system check
       * @param array $paymentProcessor
       *
       * @return string
       */
      private static function getTitle($paymentProcessor) {
        if (!empty($paymentProcessor['is_test'])) {
          $paymentProcessor['name'] .= ' (test)';
        }
        return E::ts('Stripe Payment Processor: %1 (%2)', [
          1 => $paymentProcessor['name'],
          2 => $paymentProcessor['id'],
        ]);
      }
    
    
    mattwire's avatar
    mattwire committed
      /**
       * Create a new webhook for payment processor
       *
       * @param int $paymentProcessorId
       */
      public static function createWebhook($paymentProcessorId) {
    
        $processor = new CRM_Core_Payment_Stripe('', civicrm_api3('PaymentProcessor', 'getsingle', ['id' => $paymentProcessorId]));
        $processor->setAPIParams();
    
    mattwire's avatar
    mattwire committed
    
        $params = [
          'enabled_events' => self::getDefaultEnabledEvents(),
    
    mattwire's avatar
    mattwire committed
          'url' => self::getWebhookPath($paymentProcessorId),
    
    mattwire's avatar
    mattwire committed
          'api_version' => CRM_Core_Payment_Stripe::getApiVersion(),
          'connect' => FALSE,
        ];
        \Stripe\WebhookEndpoint::create($params);
      }
    
    
    mattwire's avatar
    mattwire committed
      /**
       * Check and update existing webhook
       *
       * @param array $webhook
    
       * @return array of correction params. Empty array if it's OK.
    
    mattwire's avatar
    mattwire committed
       */
    
      public static function checkWebhook($webhook) {
        $params = [];
    
    
        if (empty($webhook['api_version']) || ($webhook['api_version'] !== CRM_Core_Payment_Stripe::API_VERSION)) {
    
    mattwire's avatar
    mattwire committed
          $params['api_version'] = CRM_Core_Payment_Stripe::API_VERSION;
        }
    
    mattwire's avatar
    mattwire committed
        if (array_diff(self::getDefaultEnabledEvents(), $webhook['enabled_events'])) {
          $params['enabled_events'] = self::getDefaultEnabledEvents();
        }
    
    mattwire's avatar
    mattwire committed
      }
    
      /**
       * List of webhooks we currently handle
       * @return array
       */
      public static function getDefaultEnabledEvents() {
        return [
          'invoice.payment_succeeded',
          'invoice.payment_failed',
          'charge.failed',
          'charge.refunded',
          'charge.succeeded',
          'customer.subscription.updated',
          'customer.subscription.deleted',
        ];
      }
    
    }