Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 400 and 402] [Versions 401 and 402]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * This class contains a list of webservice functions related to the PayPal payment gateway.
  19   *
  20   * @package    paygw_paypal
  21   * @copyright  2020 Shamim Rezaie <shamim@moodle.com>
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  declare(strict_types=1);
  26  
  27  namespace paygw_paypal\external;
  28  
  29  use core_external\external_api;
  30  use core_external\external_value;
  31  use core_external\external_function_parameters;
  32  use core_payment\helper;
  33  use core_payment\helper as payment_helper;
  34  use paygw_paypal\paypal_helper;
  35  
  36  class transaction_complete extends external_api {
  37  
  38      /**
  39       * Returns description of method parameters.
  40       *
  41       * @return external_function_parameters
  42       */
  43      public static function execute_parameters() {
  44          return new external_function_parameters([
  45              'component' => new external_value(PARAM_COMPONENT, 'The component name'),
  46              'paymentarea' => new external_value(PARAM_AREA, 'Payment area in the component'),
  47              'itemid' => new external_value(PARAM_INT, 'The item id in the context of the component area'),
  48              'orderid' => new external_value(PARAM_TEXT, 'The order id coming back from PayPal'),
  49          ]);
  50      }
  51  
  52      /**
  53       * Perform what needs to be done when a transaction is reported to be complete.
  54       * This function does not take cost as a parameter as we cannot rely on any provided value.
  55       *
  56       * @param string $component Name of the component that the itemid belongs to
  57       * @param string $paymentarea
  58       * @param int $itemid An internal identifier that is used by the component
  59       * @param string $orderid PayPal order ID
  60       * @return array
  61       */
  62      public static function execute(string $component, string $paymentarea, int $itemid, string $orderid): array {
  63          global $USER, $DB;
  64  
  65          self::validate_parameters(self::execute_parameters(), [
  66              'component' => $component,
  67              'paymentarea' => $paymentarea,
  68              'itemid' => $itemid,
  69              'orderid' => $orderid,
  70          ]);
  71  
  72          $config = (object)helper::get_gateway_configuration($component, $paymentarea, $itemid, 'paypal');
  73          $sandbox = $config->environment == 'sandbox';
  74  
  75          $payable = payment_helper::get_payable($component, $paymentarea, $itemid);
  76          $currency = $payable->get_currency();
  77  
  78          // Add surcharge if there is any.
  79          $surcharge = helper::get_gateway_surcharge('paypal');
  80          $amount = helper::get_rounded_cost($payable->get_amount(), $currency, $surcharge);
  81  
  82          $paypalhelper = new paypal_helper($config->clientid, $config->secret, $sandbox);
  83          $orderdetails = $paypalhelper->get_order_details($orderid);
  84  
  85          $success = false;
  86          $message = '';
  87  
  88          if ($orderdetails) {
  89              if ($orderdetails['status'] == paypal_helper::ORDER_STATUS_APPROVED &&
  90                      $orderdetails['intent'] == paypal_helper::ORDER_INTENT_CAPTURE) {
  91                  $item = $orderdetails['purchase_units'][0];
  92                  if ($item['amount']['value'] == $amount && $item['amount']['currency_code'] == $currency) {
  93                      $capture = $paypalhelper->capture_order($orderid);
  94                      if ($capture && $capture['status'] == paypal_helper::CAPTURE_STATUS_COMPLETED) {
  95                          $success = true;
  96                          // Everything is correct. Let's give them what they paid for.
  97                          try {
  98                              $paymentid = payment_helper::save_payment($payable->get_account_id(), $component, $paymentarea,
  99                                  $itemid, (int) $USER->id, $amount, $currency, 'paypal');
 100  
 101                              // Store PayPal extra information.
 102                              $record = new \stdClass();
 103                              $record->paymentid = $paymentid;
 104                              $record->pp_orderid = $orderid;
 105  
 106                              $DB->insert_record('paygw_paypal', $record);
 107  
 108                              payment_helper::deliver_order($component, $paymentarea, $itemid, $paymentid, (int) $USER->id);
 109                          } catch (\Exception $e) {
 110                              debugging('Exception while trying to process payment: ' . $e->getMessage(), DEBUG_DEVELOPER);
 111                              $success = false;
 112                              $message = get_string('internalerror', 'paygw_paypal');
 113                          }
 114                      } else {
 115                          $success = false;
 116                          $message = get_string('paymentnotcleared', 'paygw_paypal');
 117                      }
 118                  } else {
 119                      $success = false;
 120                      $message = get_string('amountmismatch', 'paygw_paypal');
 121                  }
 122              } else {
 123                  $success = false;
 124                  $message = get_string('paymentnotcleared', 'paygw_paypal');
 125              }
 126          } else {
 127              // Could not capture authorization!
 128              $success = false;
 129              $message = get_string('cannotfetchorderdatails', 'paygw_paypal');
 130          }
 131  
 132          return [
 133              'success' => $success,
 134              'message' => $message,
 135          ];
 136      }
 137  
 138      /**
 139       * Returns description of method result value.
 140       *
 141       * @return external_function_parameters
 142       */
 143      public static function execute_returns() {
 144          return new external_function_parameters([
 145              'success' => new external_value(PARAM_BOOL, 'Whether everything was successful or not.'),
 146              'message' => new external_value(PARAM_RAW, 'Message (usually the error message).'),
 147          ]);
 148      }
 149  }