first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
+156
View File
@@ -0,0 +1,156 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Class account
*
* @package core_payment
* @copyright 2020 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_payment;
use core\persistent;
/**
* Class account
*
* @package core_payment
* @copyright 2020 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class account extends persistent {
/**
* Database table.
*/
const TABLE = 'payment_accounts';
/** @var array */
protected $gateways;
/**
* Return the definition of the properties of this model.
*
* @return array
*/
protected static function define_properties(): array {
return array(
'name' => [
'type' => PARAM_TEXT,
],
'idnumber' => [
'type' => PARAM_RAW_TRIMMED,
],
'contextid' => [
'type' => PARAM_INT,
'default' => function() {
return \context_system::instance()->id;
}
],
'enabled' => [
'type' => PARAM_BOOL,
'default' => true
],
'archived' => [
'type' => PARAM_BOOL,
'default' => false
],
);
}
/**
* Account context
*
* @return \context
* @throws \coding_exception
*/
public function get_context(): \context {
return \context::instance_by_id($this->get('contextid'));
}
/**
* Account name ready for display
*
* @return string
* @throws \coding_exception
*/
public function get_formatted_name(): string {
return format_string($this->get('name'), true, ['context' => $this->get_context(), 'escape' => false]);
}
/**
* Manage account url
*
* @param array $extraparams
* @return \moodle_url
* @throws \coding_exception
* @throws \moodle_exception
*/
public function get_edit_url(array $extraparams = []): \moodle_url {
return new \moodle_url('/payment/manage_account.php',
($this->get('id') ? ['id' => $this->get('id')] : []) + $extraparams);
}
/**
* List of gateways configured (or possible) for this account
*
* @param bool $enabledpluginsonly only return payment plugins that are enabled
* @return account_gateway[]
* @throws \coding_exception
*/
public function get_gateways(bool $enabledpluginsonly = true): array {
$id = $this->get('id');
if (!$id) {
return [];
}
if ($this->gateways === null) {
\core_component::get_plugin_list('paygw');
$this->gateways = [];
foreach (\core_component::get_plugin_list('paygw') as $gatewayname => $unused) {
$gateway = account_gateway::get_record(['accountid' => $id, 'gateway' => $gatewayname]);
if (!$gateway) {
$gateway = new account_gateway(0, (object)['accountid' => $id, 'gateway' => $gatewayname,
'enabled' => false, 'config' => null]);
}
$this->gateways[$gatewayname] = $gateway;
}
}
if ($enabledpluginsonly) {
$enabledplugins = \core\plugininfo\paygw::get_enabled_plugins();
return array_intersect_key($this->gateways, $enabledplugins);
}
return $this->gateways;
}
/**
* Is this account available (used in management interface)
*
* @return bool
* @throws \coding_exception
*/
public function is_available(): bool {
if (!$this->get('id') || !$this->get('enabled')) {
return false;
}
foreach ($this->get_gateways() as $gateway) {
if ($gateway->get('id') && $gateway->get('enabled')) {
return true;
}
}
return false;
}
}
+106
View File
@@ -0,0 +1,106 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Class account_gateway
*
* @package core_payment
* @copyright 2020 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_payment;
use core\persistent;
/**
* Class account_gateway
*
* @package core_payment
* @copyright 2020 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class account_gateway extends persistent {
/**
* Database table.
*/
const TABLE = 'payment_gateways';
/**
* Return the definition of the properties of this model.
*
* @return array
*/
protected static function define_properties(): array {
return array(
'accountid' => [
'type' => PARAM_INT,
],
'gateway' => [
'type' => PARAM_COMPONENT,
],
'enabled' => [
'type' => PARAM_BOOL,
'default' => true
],
'config' => [
'type' => PARAM_RAW,
'optional' => true,
'null' => NULL_ALLOWED,
'default' => null
],
);
}
/**
* Return the gateway name ready for display
*
* @return string
*/
public function get_display_name(): string {
return get_string('pluginname', 'paygw_' . $this->get('gateway'));
}
/**
* Gateway management url
*
* @return \moodle_url
*/
public function get_edit_url(): \moodle_url {
$params = $this->get('id') ? ['id' => $this->get('id')] :
['accountid' => $this->get('accountid'), 'gateway' => $this->get('gateway')];
return new \moodle_url('/payment/manage_gateway.php', $params);
}
/**
* Get corresponding account
*
* @return account
*/
public function get_account(): account {
return new account($this->get('accountid'));
}
/**
* Parse configuration from the json-encoded stored value
*
* @return array
*/
public function get_configuration(): array {
$config = @json_decode($this->get('config'), true);
return ($config && is_array($config)) ? $config : [];
}
}
+94
View File
@@ -0,0 +1,94 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_payment\event;
use core\event\base;
use core_payment\account;
/**
* Class account_created
*
* @package core_payment
* @copyright 2020 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Class account_created
*
* @package core_payment
* @copyright 2020 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class account_created extends base {
/**
* Initialise event parameters.
*/
protected function init() {
$this->data['objecttable'] = 'payment_accounts';
$this->data['crud'] = 'c';
$this->data['edulevel'] = self::LEVEL_OTHER;
}
/**
* Create an instance of the event and add a record snapshot
*
* @param account $account
* @return base
* @throws \coding_exception
*/
public static function create_from_account(account $account) {
$eventparams = [
'objectid' => $account->get('id'),
'context' => $account->get_context(),
'other' => ['name' => $account->get('name')]
];
$event = self::create($eventparams);
$event->add_record_snapshot($event->objecttable, $account->to_record());
return $event;
}
/**
* Returns localised event name.
*
* @return string
*/
public static function get_name() {
return get_string('eventaccountcreated', 'payment');
}
/**
* Returns non-localised event description with id's for admin use only.
*
* @return string
*/
public function get_description() {
$name = s($this->other['name']);
return "The user with id '$this->userid' created payment account with id '$this->objectid' and the name '{$name}'.";
}
/**
* Returns relevant URL.
*
* @return \moodle_url
*/
public function get_url() {
return new \moodle_url('/payment/accounts.php');
}
}
+94
View File
@@ -0,0 +1,94 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_payment\event;
use core\event\base;
use core_payment\account;
/**
* Class account_deleted
*
* @package core_payment
* @copyright 2020 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Class account_deleted
*
* @package core_payment
* @copyright 2020 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class account_deleted extends base {
/**
* Initialise event parameters.
*/
protected function init() {
$this->data['objecttable'] = 'payment_accounts';
$this->data['crud'] = 'd';
$this->data['edulevel'] = self::LEVEL_OTHER;
}
/**
* Create an instance of the event and add a record snapshot
*
* @param account $account
* @return base
* @throws \coding_exception
*/
public static function create_from_account(account $account) {
$eventparams = [
'objectid' => $account->get('id'),
'context' => $account->get_context(),
'other' => ['name' => $account->get('name')]
];
$event = self::create($eventparams);
$event->add_record_snapshot($event->objecttable, $account->to_record());
return $event;
}
/**
* Returns localised event name.
*
* @return string
*/
public static function get_name() {
return get_string('eventaccountdeleted', 'payment');
}
/**
* Returns non-localised event description with id's for admin use only.
*
* @return string
*/
public function get_description() {
$name = s($this->other['name']);
return "The user with id '$this->userid' deleted payment account with id '$this->objectid' and the name '{$name}'.";
}
/**
* Returns relevant URL.
*
* @return \moodle_url
*/
public function get_url() {
return new \moodle_url('/payment/accounts.php');
}
}
+101
View File
@@ -0,0 +1,101 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_payment\event;
use core\event\base;
use core_payment\account;
/**
* Class account_updated
*
* @package core_payment
* @copyright 2020 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Class account_updated
*
* @package core_payment
* @copyright 2020 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class account_updated extends base {
/**
* Initialise event parameters.
*/
protected function init() {
$this->data['objecttable'] = 'payment_accounts';
$this->data['crud'] = 'u';
$this->data['edulevel'] = self::LEVEL_OTHER;
}
/**
* Create an instance of the event and add a record snapshot
*
* @param account $account
* @param array $other
* @return base
*/
public static function create_from_account(account $account, array $other = []) {
$eventparams = [
'objectid' => $account->get('id'),
'context' => $account->get_context(),
'other' => ['name' => $account->get('name')] + $other
];
$event = self::create($eventparams);
$event->add_record_snapshot($event->objecttable, $account->to_record());
return $event;
}
/**
* Returns localised event name.
*
* @return string
*/
public static function get_name() {
return get_string('eventaccountupdated', 'payment');
}
/**
* Returns non-localised event description with id's for admin use only.
*
* @return string
*/
public function get_description() {
$name = s($this->other['name']);
if (!empty($this->other['archived'])) {
$verb = 'archived';
} else if (!empty($this->other['restored'])) {
$verb = 'restored';
} else {
$verb = 'updated';
}
return "The user with id '$this->userid' $verb payment account with id '$this->objectid' and the name '{$name}'.";
}
/**
* Returns relevant URL.
*
* @return \moodle_url
*/
public function get_url() {
return new \moodle_url('/payment/accounts.php');
}
}
+102
View File
@@ -0,0 +1,102 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This is the external API for this component.
*
* @package core_payment
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_payment\external;
use core_payment\helper;
use core_external\external_api;
use core_external\external_value;
use core_external\external_single_structure;
use core_external\external_multiple_structure;
use core_external\external_function_parameters;
class get_available_gateways extends external_api {
/**
* Returns description of method parameters.
*
* @return external_function_parameters
*/
public static function execute_parameters(): external_function_parameters {
return new external_function_parameters([
'component' => new external_value(PARAM_COMPONENT, 'Component'),
'paymentarea' => new external_value(PARAM_AREA, 'Payment area in the component'),
'itemid' => new external_value(PARAM_INT, 'An identifier for payment area in the component')
]);
}
/**
* Returns the list of gateways that can process payments in the given currency.
*
* @param string $component
* @param string $paymentarea
* @param int $itemid
* @return \stdClass[]
*/
public static function execute(string $component, string $paymentarea, int $itemid): array {
$params = external_api::validate_parameters(self::execute_parameters(), [
'component' => $component,
'paymentarea' => $paymentarea,
'itemid' => $itemid,
]);
$list = [];
$gateways = helper::get_available_gateways($params['component'], $params['paymentarea'], $params['itemid']);
$payable = helper::get_payable($params['component'], $params['paymentarea'], $params['itemid']);
$amount = $payable->get_amount();
$currency = $payable->get_currency();
foreach ($gateways as $gateway) {
$surcharge = helper::get_gateway_surcharge($gateway);
$list[] = (object)[
'shortname' => $gateway,
'name' => get_string('gatewayname', 'paygw_' . $gateway),
'description' => get_string('gatewaydescription', 'paygw_' . $gateway),
'surcharge' => $surcharge,
'cost' => helper::get_cost_as_string($amount, $currency, $surcharge),
];
}
return $list;
}
/**
* Returns description of method result value.
*
* @return external_multiple_structure
*/
public static function execute_returns(): external_multiple_structure {
return new external_multiple_structure(
new external_single_structure([
'shortname' => new external_value(PARAM_PLUGIN, 'Name of the plugin'),
'name' => new external_value(PARAM_TEXT, 'Human readable name of the gateway'),
'description' => new external_value(PARAM_RAW, 'description of the gateway'),
'surcharge' => new external_value(PARAM_INT, 'percentage of surcharge when using the gateway'),
'cost' => new external_value(PARAM_TEXT,
'Cost in human-readable form (amount plus surcharge with currency sign)'),
])
);
}
}
+66
View File
@@ -0,0 +1,66 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Class account
*
* @package core_payment
* @copyright 2020 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_payment\form;
use core\form\persistent;
/**
* Class account
*
* @package core_payment
* @copyright 2020 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class account extends persistent {
/** @var string The persistent class. */
protected static $persistentclass = 'core_payment\account';
/**
* Define the form - called by parent constructor
*/
public function definition() {
$mform = $this->_form;
$mform->addElement('hidden', 'id');
$mform->addElement('hidden', 'contextid');
$mform->addElement('text', 'name', get_string('accountname', 'payment'), 'maxlength="255"');
$mform->addHelpButton('name', 'accountname', 'payment');
$mform->setType('name', PARAM_TEXT);
$mform->addRule('name', get_string('required'), 'required', null, 'client');
$mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'server');
$mform->addElement('text', 'idnumber', get_string('accountidnumber', 'payment'), 'maxlength="100"');
$mform->addHelpButton('idnumber', 'accountidnumber', 'payment');
$mform->setType('idnumber', PARAM_RAW_TRIMMED);
$mform->addRule('idnumber', get_string('maximumchars', '', 100), 'maxlength', 100, 'server');
$mform->addElement('static', 'staticinfo', '', get_string('accountconfignote', 'payment'));
$mform->addElement('advcheckbox', 'enabled', get_string('enable'));
$this->add_action_buttons();
}
}
+147
View File
@@ -0,0 +1,147 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Class account_gateway
*
* @package core_payment
* @copyright 2020 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_payment\form;
use core\form\persistent;
/**
* Class account_gateway
*
* @package core_payment
* @copyright 2020 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class account_gateway extends persistent {
/** @var string The persistent class. */
protected static $persistentclass = \core_payment\account_gateway::class;
protected static $fieldstoremove = ['accountname', 'gatewayname', 'submitbutton'];
/**
* Define the form - called by parent constructor
*/
public function definition() {
$mform = $this->_form;
$mform->addElement('hidden', 'id');
$mform->addElement('hidden', 'accountid');
$mform->addElement('hidden', 'gateway');
$mform->addElement('static', 'accountname', get_string('accountname', 'payment'),
$this->get_gateway_persistent()->get_account()->get_formatted_name());
$mform->addElement('static', 'gatewayname', get_string('type_paygw', 'plugin'),
$this->get_gateway_persistent()->get_display_name());
$mform->addElement('advcheckbox', 'enabled', get_string('enable'));
/** @var \core_payment\gateway $classname */
$classname = '\paygw_' . $this->get_gateway_persistent()->get('gateway') . '\gateway';
if (class_exists($classname)) {
$classname::add_configuration_to_gateway_form($this);
}
$this->add_action_buttons();
}
/**
* Form validation
*
* @param \stdClass $data
* @param array $files
* @param array $errors
*/
protected function extra_validation($data, $files, array &$errors) {
/** @var \core_payment\gateway $classname */
$classname = '\paygw_' . $this->get_gateway_persistent()->get('gateway') . '\gateway';
if (class_exists($classname)) {
$classname::validate_gateway_form($this, $data, $files, $errors);
}
}
/**
* Exposes the protected attribute to be accessed by the \core_payment\gateway callback
*
* @return \MoodleQuickForm
*/
public function get_mform(): \MoodleQuickForm {
return $this->_form;
}
/**
* Exposes the protected attribute to be accessed by the \core_payment\gateway callback
*
* @return \core_payment\account_gateway
*/
public function get_gateway_persistent(): \core_payment\account_gateway {
return $this->get_persistent();
}
/**
* Filter out the foreign fields of the persistent.
*
* This can be overridden to filter out more complex fields.
*
* @param \stdClass $data The data to filter the fields out of.
* @return \stdClass.
*/
protected function filter_data_for_persistent($data) {
$data = parent::filter_data_for_persistent($data);
return (object) array_intersect_key((array)$data, \core_payment\account_gateway::properties_definition());
}
/**
* Overwrite parent method to json encode config
*
* @return object|\stdClass|null
* @throws \coding_exception
*/
public function get_data() {
if (!$data = parent::get_data()) {
return $data;
}
// Everything that is not a property of the account_gateway class is a gateway config.
$data = (array)$data;
$properties = \core_payment\account_gateway::properties_definition() + ['id' => 1];
$config = array_diff_key($data, $properties, ['timemodified' => 1, 'timecreated' => 1]);
$data = array_intersect_key($data, $properties);
$data['config'] = json_encode($config);
return (object)$data;
}
/**
* Overwrite parent method to json decode config
*
* @param array|\stdClass $values
*/
public function set_data($values) {
if (($config = isset($values->config) ? @json_decode($values->config, true) : null) && is_array($config)) {
$values = (object)((array)$values + $config);
}
unset($values->config);
parent::set_data($values);
}
}
+66
View File
@@ -0,0 +1,66 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Contains base class for payment gateways.
*
* @package core_payment
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_payment;
/**
* Base class for payment gateways.
*
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class gateway {
/**
* Returns the list of currencies that the payment gateway supports.
*
* @return string[] An array of the currency codes in the three-character ISO-4217 format
*/
abstract public static function get_supported_currencies(): array;
/**
* Configuration form for the gateway instance
*
* Use $form->get_mform() to access the \MoodleQuickForm instance
*
* @param \core_payment\form\account_gateway $form
*/
abstract public static function add_configuration_to_gateway_form(\core_payment\form\account_gateway $form): void;
/**
* Validates the gateway configuration form.
*
* Needs to be overridden to make sure the incomplete configuration can not be enabled.
*
* @param \core_payment\form\account_gateway $form
* @param \stdClass $data
* @param array $files
* @param array $errors form errors (passed by reference)
*/
public static function validate_gateway_form(\core_payment\form\account_gateway $form,
\stdClass $data, array $files, array &$errors): void {
if ($data->enabled) {
$errors['enabled'] = get_string('gatewaycannotbeenabled', 'payment');
}
}
}
+416
View File
@@ -0,0 +1,416 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Contains helper class for the payment subsystem.
*
* @package core_payment
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_payment;
use core_payment\event\account_created;
use core_payment\event\account_deleted;
use core_payment\event\account_updated;
/**
* Helper class for the payment subsystem.
*
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class helper {
/**
* Returns an accumulated list of supported currencies by all payment gateways.
*
* @return string[] An array of the currency codes in the three-character ISO-4217 format
*/
public static function get_supported_currencies(): array {
$currencies = [];
$plugins = \core_plugin_manager::instance()->get_enabled_plugins('paygw');
foreach ($plugins as $plugin) {
/** @var \paygw_paypal\gateway $classname */
$classname = '\paygw_' . $plugin . '\gateway';
$currencies = array_merge($currencies, component_class_callback($classname, 'get_supported_currencies', [], []));
}
$currencies = array_unique($currencies);
return $currencies;
}
/**
* Returns the list of gateways that can process payments in the given currency.
*
* @param string $component Name of the component that the paymentarea and itemid belong to
* @param string $paymentarea Payment area
* @param int $itemid An identifier that is known to the component
* @return string[]
*/
public static function get_available_gateways(string $component, string $paymentarea, int $itemid): array {
$gateways = [];
$payable = static::get_payable($component, $paymentarea, $itemid);
$account = new account($payable->get_account_id());
if (!$account->get('id') || !$account->get('enabled')) {
return $gateways;
}
$currency = $payable->get_currency();
foreach ($account->get_gateways() as $plugin => $gateway) {
if (!$gateway->get('enabled')) {
continue;
}
/** @var gateway $classname */
$classname = '\paygw_' . $plugin . '\gateway';
$currencies = component_class_callback($classname, 'get_supported_currencies', [], []);
if (in_array($currency, $currencies)) {
$gateways[] = $plugin;
}
}
return $gateways;
}
/**
* Rounds the cost based on the currency fractional digits, can also apply surcharge
*
* @param float $amount amount in the currency units
* @param string $currency currency, used for calculating the number of fractional digits
* @param float $surcharge surcharge in percents
* @return float
*/
public static function get_rounded_cost(float $amount, string $currency, float $surcharge = 0): float {
$amount = $amount * (100 + $surcharge) / 100;
$locale = get_string('localecldr', 'langconfig');
$fmt = \NumberFormatter::create($locale, \NumberFormatter::CURRENCY);
$localisedcost = numfmt_format_currency($fmt, $amount, $currency);
return numfmt_parse_currency($fmt, $localisedcost, $currency);
}
/**
* Returns human-readable amount with correct number of fractional digits and currency indicator, can also apply surcharge
*
* @param float $amount amount in the currency units
* @param string $currency The currency
* @param float $surcharge surcharge in percents
* @return string
*/
public static function get_cost_as_string(float $amount, string $currency, float $surcharge = 0): string {
$amount = $amount * (100 + $surcharge) / 100;
$locale = get_string('localecldr', 'langconfig');
$fmt = \NumberFormatter::create($locale, \NumberFormatter::CURRENCY);
$localisedcost = numfmt_format_currency($fmt, $amount, $currency);
return $localisedcost;
}
/**
* Returns the percentage of surcharge that is applied when using a gateway
*
* @param string $gateway Name of the gateway
* @return float
*/
public static function get_gateway_surcharge(string $gateway): float {
return (float)get_config('paygw_' . $gateway, 'surcharge');
}
/**
* Returns the attributes to place on a pay button.
*
* @param string $component Name of the component that the paymentarea and itemid belong to
* @param string $paymentarea Payment area
* @param int $itemid An internal identifier that is used by the component
* @param string $description Description of the payment
* @return array
*/
public static function gateways_modal_link_params(string $component, string $paymentarea, int $itemid,
string $description): array {
$payable = static::get_payable($component, $paymentarea, $itemid);
$successurl = static::get_success_url($component, $paymentarea, $itemid);
return [
'id' => 'gateways-modal-trigger',
'role' => 'button',
'data-action' => 'core_payment/triggerPayment',
'data-component' => $component,
'data-paymentarea' => $paymentarea,
'data-itemid' => $itemid,
'data-cost' => static::get_cost_as_string($payable->get_amount(), $payable->get_currency()),
'data-description' => $description,
'data-successurl' => $successurl->out(false),
];
}
/**
* Get the name of the service provider class
*
* @param string $component The component
* @return string
* @throws \coding_exception
*/
private static function get_service_provider_classname(string $component) {
$providerclass = "$component\\payment\\service_provider";
if (class_exists($providerclass)) {
$rc = new \ReflectionClass($providerclass);
if ($rc->implementsInterface(local\callback\service_provider::class)) {
return $providerclass;
}
}
throw new \coding_exception("$component does not have an eligible implementation of payment service_provider.");
}
/**
* Asks the payable from the related component.
*
* @param string $component Name of the component that the paymentarea and itemid belong to
* @param string $paymentarea Payment area
* @param int $itemid An internal identifier that is used by the component
* @return local\entities\payable
*/
public static function get_payable(string $component, string $paymentarea, int $itemid): local\entities\payable {
$providerclass = static::get_service_provider_classname($component);
return component_class_callback($providerclass, 'get_payable', [$paymentarea, $itemid]);
}
/**
* Fetches the URL of the page the user should be redirected to from the related component
*
* @param string $component Name of the component that the paymentarea and itemid belong to
* @param string $paymentarea Payment area
* @param int $itemid An identifier that is known to the component
* @return \moodle_url
*/
public static function get_success_url(string $component, string $paymentarea, int $itemid): \moodle_url {
$providerclass = static::get_service_provider_classname($component);
return component_class_callback($providerclass, 'get_success_url', [$paymentarea, $itemid]);
}
/**
* Returns the gateway configuration for given component and gateway
*
* @param string $component Name of the component that the paymentarea and itemid belong to
* @param string $paymentarea Payment area
* @param int $itemid An identifier that is known to the component
* @param string $gatewayname The gateway name
* @return array
* @throws \moodle_exception
*/
public static function get_gateway_configuration(string $component, string $paymentarea, int $itemid,
string $gatewayname): array {
$payable = self::get_payable($component, $paymentarea, $itemid);
$gateway = null;
$account = new account($payable->get_account_id());
if ($account && $account->get('enabled')) {
$gateway = $account->get_gateways()[$gatewayname] ?? null;
}
if (!$gateway) {
throw new \moodle_exception('gatewaynotfound', 'payment');
}
return $gateway->get_configuration();
}
/**
* Delivers what the user paid for.
*
* @uses \core_payment\local\callback\service_provider::deliver_order()
*
* @param string $component Name of the component that the paymentarea and itemid belong to
* @param string $paymentarea Payment area
* @param int $itemid An internal identifier that is used by the component
* @param int $paymentid payment id as inserted into the 'payments' table, if needed for reference
* @param int $userid The userid the order is going to deliver to
* @return bool Whether successful or not
*/
public static function deliver_order(string $component, string $paymentarea, int $itemid, int $paymentid, int $userid): bool {
$providerclass = static::get_service_provider_classname($component);
$result = component_class_callback($providerclass, 'deliver_order', [$paymentarea, $itemid, $paymentid, $userid]);
return $result;
}
/**
* Stores essential information about the payment and returns the "id" field of the payment record in DB.
* Each payment gateway may then store the additional information their way.
*
* @param int $accountid Account id
* @param string $component Name of the component that the paymentarea and itemid belong to
* @param string $paymentarea Payment area
* @param int $itemid An internal identifier that is used by the component
* @param int $userid Id of the user who is paying
* @param float $amount Amount of payment
* @param string $currency Currency of payment
* @param string $gateway The gateway that is used for the payment
* @return int
*/
public static function save_payment(int $accountid, string $component, string $paymentarea, int $itemid, int $userid,
float $amount, string $currency, string $gateway): int {
global $DB;
$record = new \stdClass();
$record->component = $component;
$record->paymentarea = $paymentarea;
$record->itemid = $itemid;
$record->userid = $userid;
$record->amount = $amount;
$record->currency = $currency;
$record->gateway = $gateway;
$record->accountid = $accountid;
$record->timecreated = $record->timemodified = time();
$id = $DB->insert_record('payments', $record);
return $id;
}
/**
* This functions adds the settings that are common for all payment gateways.
*
* @param \admin_settingpage $settings The settings object
* @param string $gateway The gateway name prefixed with paygw_
*/
public static function add_common_gateway_settings(\admin_settingpage $settings, string $gateway): void {
$settings->add(new \admin_setting_configtext($gateway . '/surcharge', get_string('surcharge', 'core_payment'),
get_string('surcharge_desc', 'core_payment'), 0, PARAM_INT));
}
/**
* Save a new or edited payment account (used in management interface)
*
* @param \stdClass $data
* @return account
*/
public static function save_payment_account(\stdClass $data): account {
if (empty($data->id)) {
$account = new account(0, $data);
$account->save();
account_created::create_from_account($account)->trigger();
} else {
$account = new account($data->id);
$account->from_record($data);
$account->save();
account_updated::create_from_account($account)->trigger();
}
return $account;
}
/**
* Delete a payment account (used in management interface)
*
* @param account $account
*/
public static function delete_payment_account(account $account): void {
global $DB;
if ($DB->record_exists('payments', ['accountid' => $account->get('id')])) {
$account->set('archived', 1);
$account->save();
account_updated::create_from_account($account, ['archived' => 1])->trigger();
return;
}
foreach ($account->get_gateways(false) as $gateway) {
if ($gateway->get('id')) {
$gateway->delete();
}
}
$event = account_deleted::create_from_account($account);
$account->delete();
$event->trigger();
}
/**
* Restore archived payment account (used in management interface)
*
* @param account $account
*/
public static function restore_payment_account(account $account): void {
$account->set('archived', 0);
$account->save();
account_updated::create_from_account($account, ['restored' => 1])->trigger();
}
/**
* Save a payment gateway linked to an existing account (used in management interface)
*
* @param \stdClass $data
* @return account_gateway
*/
public static function save_payment_gateway(\stdClass $data): account_gateway {
if (empty($data->id)) {
$records = account_gateway::get_records(['accountid' => $data->accountid, 'gateway' => $data->gateway]);
if ($records) {
$gateway = reset($records);
} else {
$gateway = new account_gateway(0, $data);
}
} else {
$gateway = new account_gateway($data->id);
}
unset($data->accountid, $data->gateway, $data->id);
$gateway->from_record($data);
$account = $gateway->get_account();
$gateway->save();
account_updated::create_from_account($account)->trigger();
return $gateway;
}
/**
* Returns the list of payment accounts in the given context (used in management interface)
*
* @param \context $context
* @return account[]
*/
public static function get_payment_accounts_to_manage(\context $context, bool $showarchived = false): array {
$records = account::get_records(['contextid' => $context->id] + ($showarchived ? [] : ['archived' => 0]));
\core_collator::asort_objects_by_method($records, 'get_formatted_name');
return $records;
}
/**
* Get list of accounts available in the given context
*
* @param \context $context
* @return array
*/
public static function get_payment_accounts_menu(\context $context): array {
global $DB;
[$sql, $params] = $DB->get_in_or_equal($context->get_parent_context_ids(true));
$accounts = array_filter(account::get_records_select('contextid '.$sql, $params), function($account) {
return $account->is_available() && !$account->get('archived');
});
return array_map(function($account) {
return $account->get_formatted_name();
}, $accounts);
}
}
@@ -0,0 +1,67 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains the \core_payment\local\local\callback\service_provider interface.
*
* Plugins should implement this if they use payment subsystem.
*
* @package core_payment
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_payment\local\callback;
/**
* The service_provider interface for plugins to provide callbacks which are needed by the payment subsystem.
*
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
interface service_provider {
/**
* Callback function that returns the cost of the given item in the specified payment area,
* along with the accountid that payments are paid to.
*
* @param string $paymentarea Payment area
* @param int $itemid An identifier that is known to the plugin
* @return \core_payment\local\entities\payable
*/
public static function get_payable(string $paymentarea, int $itemid): \core_payment\local\entities\payable;
/**
* Callback function that returns the URL of the page the user should be redirected to in the case of a successful payment.
*
* @param string $paymentarea Payment area
* @param int $itemid An identifier that is known to the plugin
* @return \moodle_url
*/
public static function get_success_url(string $paymentarea, int $itemid): \moodle_url;
/**
* Callback function that delivers what the user paid for to them.
*
* @param string $paymentarea Payment area
* @param int $itemid An identifier that is known to the plugin
* @param int $paymentid payment id as inserted into the 'payments' table, if needed for reference
* @param int $userid The userid the order is going to deliver to
*
* @return bool Whether successful or not
*/
public static function deliver_order(string $paymentarea, int $itemid, int $paymentid, int $userid): bool;
}
@@ -0,0 +1,70 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* The payable class.
*
* @package core_payment
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_payment\local\entities;
/**
* The payable class.
*
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class payable {
private $amount;
private $currency;
private $accountid;
public function __construct(float $amount, string $currency, int $accountid) {
$this->amount = $amount;
$this->currency = $currency;
$this->accountid = $accountid;
}
/**
* Get the amount of the payable cost.
*
* @return float
*/
public function get_amount(): float {
return $this->amount;
}
/**
* Get the currency of the payable cost.
*
* @return string
*/
public function get_currency(): string {
return $this->currency;
}
/**
* Get the id of the payment account the cost is payable to.
*
* @return int
*/
public function get_account_id(): int {
return $this->accountid;
}
}
@@ -0,0 +1,69 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_payment\privacy;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\approved_userlist;
use core_privacy\local\request\userlist;
use context;
interface consumer_provider {
/**
* Return contextid for the provided payment data
*
* @param string $paymentarea Payment area
* @param int $itemid The item id
* @return int|null
*/
public static function get_contextid_for_payment(string $paymentarea, int $itemid): ?int;
/**
* Get the list of users who have data within a context.
*
* @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
*/
public static function get_users_in_context(userlist $userlist);
/**
* Export all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts to export information for.
*/
public static function export_user_data(approved_contextlist $contextlist);
/**
* Delete all data for all users in the specified context.
*
* @param context $context The specific context to delete data for.
*/
public static function delete_data_for_all_users_in_context(context $context);
/**
* Delete all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
*/
public static function delete_data_for_user(approved_contextlist $contextlist);
/**
* Delete multiple users within a single context.
*
* @param approved_userlist $userlist The approved context and user information to delete information for.
*/
public static function delete_data_for_users(approved_userlist $userlist);
}
@@ -0,0 +1,37 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_payment\privacy;
interface paygw_provider {
/**
* Export all user data for the specified payment record, and the given context.
*
* @param \context $context Context
* @param array $subcontext The location within the current context that the payment data belongs
* @param \stdClass $payment The payment record
*/
public static function export_payment_data(\context $context, array $subcontext, \stdClass $payment);
/**
* Delete all user data related to the given payments.
*
* @param string $paymentsql SQL query that selects payment.id field for the payments
* @param array $paymentparams Array of parameters for $paymentsql
*/
public static function delete_data_for_payment_sql(string $paymentsql, array $paymentparams);
}
+338
View File
@@ -0,0 +1,338 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Privacy Subsystem implementation for core_payment.
*
* @package core_payment
* @category privacy
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_payment\privacy;
use core_privacy\local\metadata\collection;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\approved_userlist;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\transform;
use core_privacy\local\request\userlist;
use core_privacy\local\request\writer;
use core_payment\helper as payment_helper;
/**
* Privacy Subsystem implementation for core_payment.
*
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements
// This component has data.
// We need to return all payment information where the user is
// listed in the payment.userid field.
// We may also need to fetch this informtion from individual plugins in some cases.
// e.g. to fetch the full and other gateway-specific meta-data.
\core_privacy\local\metadata\provider,
// This is a subsysytem which provides information to core.
\core_privacy\local\request\subsystem\provider,
// This is a subsysytem which provides information to plugins.
\core_privacy\local\request\subsystem\plugin_provider,
// This plugin is capable of determining which users have data within it.
\core_privacy\local\request\core_userlist_provider,
// This plugin is capable of determining which users have data within it for the plugins it provides data to.
\core_privacy\local\request\shared_userlist_provider
{
/**
* Returns meta data about this system.
*
* @param collection $collection The initialised collection to add items to.
* @return collection A listing of user data stored through this system.
*/
public static function get_metadata(collection $collection): collection {
// The 'payments' table contains data about payments.
$collection->add_database_table('payments', [
'userid' => 'privacy:metadata:database:payments:userid',
'amount' => 'privacy:metadata:database:payments:amount',
'currency' => 'privacy:metadata:database:payments:currency',
'gateway' => 'privacy:metadata:database:payments:gateway',
'timecreated' => 'privacy:metadata:database:payments:timecreated',
'timemodified' => 'privacy:metadata:database:payments:timemodified',
], 'privacy:metadata:database:payments');
return $collection;
}
/**
* Get the list of users who have data within a context.
*
* @param int $userid The user to search.
* @return contextlist The contextlist containing the list of contexts used in this plugin.
*/
public static function get_contexts_for_userid(int $userid): contextlist {
global $DB;
$contextids = [];
$payments = $DB->get_recordset('payments', ['userid' => $userid]);
foreach ($payments as $payment) {
$contextids[] = \core_privacy\manager::component_class_callback(
$payment->component,
consumer_provider::class,
'get_contextid_for_payment',
[$payment->paymentarea, $payment->itemid]
) ?: SYSCONTEXTID;
}
$payments->close();
$contextlist = new contextlist();
if (!empty($contextids)) {
[$insql, $inparams] = $DB->get_in_or_equal(array_unique($contextids), SQL_PARAMS_NAMED);
$contextlist->add_from_sql("SELECT id FROM {context} WHERE id {$insql}", $inparams);
}
return $contextlist;
}
/**
* Get the list of users who have data within a context.
*
* @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
*/
public static function get_users_in_context(userlist $userlist) {
global $DB;
$providers = static::get_consumer_providers();
foreach ($providers as $provider) {
$provider::get_users_in_context($userlist);
}
// Orphaned payments.
$context = $userlist->get_context();
if ($context instanceof \context_system) {
[$notinsql, $notinparams] = $DB->get_in_or_equal($providers, SQL_PARAMS_NAMED, 'param', false);
$sql = "SELECT p.userid
FROM {payments} p
WHERE component $notinsql";
$userlist->add_from_sql('userid', $sql, $notinparams);
}
}
/**
* Export all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts to export information for.
*/
public static function export_user_data(approved_contextlist $contextlist) {
global $DB;
$providers = static::get_consumer_providers();
foreach ($providers as $provider) {
$provider::export_user_data($contextlist);
}
// Orphaned payments.
if (in_array(SYSCONTEXTID, $contextlist->get_contextids())) {
[$notinsql, $notinparams] = $DB->get_in_or_equal($providers, SQL_PARAMS_NAMED, 'param', false);
$params = ['userid' => $contextlist->get_user()->id] + $notinparams;
$orphanedpayments = $DB->get_records_sql(
"SELECT *
FROM {payments}
WHERE userid = :userid AND component $notinsql",
$params
);
foreach ($orphanedpayments as $payment) {
static::export_payment_data_for_user_in_context(
\context_system::instance(),
[''],
$payment->userid,
$payment->component,
$payment->paymentarea,
$payment->itemid
);
}
}
}
/**
* Delete all data for all users in the specified context.
*
* @param context $context The specific context to delete data for.
*/
public static function delete_data_for_all_users_in_context(\context $context) {
global $DB;
$providers = static::get_consumer_providers();
foreach ($providers as $provider) {
$provider::delete_data_for_all_users_in_context($context);
}
// Orphaned payments.
if ($context instanceof \context_system) {
[$notinsql, $params] = $DB->get_in_or_equal($providers, SQL_PARAMS_NAMED, 'param', false);
$paymentsql = "SELECT id FROM {payments} WHERE component $notinsql";
static::delete_data_for_payment_sql($paymentsql, $params);
}
}
/**
* Delete all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
*/
public static function delete_data_for_user(approved_contextlist $contextlist) {
global $DB;
$providers = static::get_consumer_providers();
foreach ($providers as $provider) {
$provider::delete_data_for_user($contextlist);
}
// Orphaned payments.
if (in_array(SYSCONTEXTID, $contextlist->get_contextids())) {
[$notinsql, $notinparams] = $DB->get_in_or_equal($providers, SQL_PARAMS_NAMED, 'param', false);
$paymentsql = "SELECT id
FROM {payments}
WHERE userid = :userid AND component $notinsql";
$paymentparams = ['userid' => $contextlist->get_user()->id] + $notinparams;
static::delete_data_for_payment_sql($paymentsql, $paymentparams);
}
}
/**
* Delete multiple users within a single context.
*
* @param approved_userlist $userlist The approved context and user information to delete information for.
*/
public static function delete_data_for_users(approved_userlist $userlist) {
global $DB;
$providers = static::get_consumer_providers();
foreach ($providers as $provider) {
$provider::delete_data_for_users($userlist);
}
// Orphaned payments.
if ($userlist->get_context() instanceof \context_system) {
[$notinsql, $notinparams] = $DB->get_in_or_equal($providers, SQL_PARAMS_NAMED, 'param', false);
[$usersql, $userparams] = $DB->get_in_or_equal($userlist->get_userids(), SQL_PARAMS_NAMED);
$paymentsql = "SELECT id
FROM {payments}
WHERE component $notinsql AND userid $usersql";
$paymentparams = $notinparams + $userparams;
static::delete_data_for_payment_sql($paymentsql, $paymentparams);
}
}
/**
* Returns the list of plugins that use the payment subsystem and implement the consumer_provider interface.
*
* @return string[] provider class names
*/
private static function get_consumer_providers(): array {
$providers = [];
foreach (array_keys(\core_component::get_plugin_types()) as $plugintype) {
$potentialproviders = \core_component::get_plugin_list_with_class($plugintype, 'privacy\provider');
foreach ($potentialproviders as $potentialprovider) {
if (is_a($potentialprovider, consumer_provider::class, true)) {
$providers[] = $potentialprovider;
}
}
}
return $providers;
}
/**
* Export all user data for the specified user, in the specified context.
*
* @param \context $context The context that the payment belongs to
* @param string[] $subpath Sub-path to be used during export
* @param int $userid User id
* @param string $component Component name
* @param string $paymentarea Payment area
* @param int $itemid An internal identifier that is used by the component
*/
public static function export_payment_data_for_user_in_context(\context $context, array $subpath, int $userid,
string $component, string $paymentarea, int $itemid) {
global $DB;
$payments = $DB->get_records('payments', [
'component' => $component,
'paymentarea' => $paymentarea,
'itemid' => $itemid,
'userid' => $userid,
]);
foreach ($payments as $payment) {
$data = (object) [
'userid' => transform::user($payment->userid),
'amount' => payment_helper::get_cost_as_string($payment->amount, $payment->currency),
'timecreated' => transform::datetime($payment->timecreated),
'timemodified' => transform::datetime($payment->timemodified),
];
$subcontext = array_merge(
[get_string('payments', 'payment')],
$subpath,
['payment-' . $payment->id]
);
writer::with_context($context)->export_data(
$subcontext,
$data
);
\core_privacy\manager::component_class_callback(
'paygw_' . $payment->gateway,
paygw_provider::class,
'export_payment_data',
[$context, $subcontext, $payment]
);
}
}
/**
* Delete all user data related to the given payments.
*
* @param string $paymentsql SQL query that selects payment.id field for the payments
* @param array $paymentparams Array of parameters for $paymentsql
*/
public static function delete_data_for_payment_sql(string $paymentsql, array $paymentparams) {
global $DB;
\core_privacy\manager::plugintype_class_callback(
'paygw',
paygw_provider::class,
'delete_data_for_payment_sql',
[$paymentsql, $paymentparams]
);
$DB->delete_records_subquery('payments', 'id', 'id', $paymentsql, $paymentparams);
}
}