mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 00:12:56 +02:00
Merge branch 'MDL-69166-master-4' of git://github.com/rezaies/moodle
This commit is contained in:
commit
931f36ce15
@ -0,0 +1,74 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Payment gateway admin setting.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_admin\local\settings;
|
||||
|
||||
/**
|
||||
* Generic class for managing plugins in a table that allows re-ordering and enable/disable of each plugin.
|
||||
*/
|
||||
class manage_payment_gateway_plugins extends \admin_setting_manage_plugins {
|
||||
/**
|
||||
* Get the admin settings section title (use get_string).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_section_title() {
|
||||
return get_string('type_paygw_plural', 'plugin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of plugin to manage.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_plugin_type() {
|
||||
return 'paygw';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the second column.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_info_column_name() {
|
||||
return get_string('supportedcurrencies', 'core_payment');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of plugin to manage.
|
||||
*
|
||||
* @param plugininfo The plugin info class.
|
||||
* @return string
|
||||
*/
|
||||
public function get_info_column($plugininfo) {
|
||||
$codes = $plugininfo->get_supported_currencies();
|
||||
|
||||
$currencies = [];
|
||||
foreach ($codes as $c) {
|
||||
$currencies[$c] = new \lang_string($c, 'core_currencies');
|
||||
}
|
||||
|
||||
return implode(get_string('listsep', 'langconfig') . ' ', $currencies);
|
||||
}
|
||||
}
|
29
admin/settings/payment.php
Normal file
29
admin/settings/payment.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Adds payments links to the admin tree
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$ADMIN->add('payment', new admin_externalpage(
|
||||
'paymentaccounts',
|
||||
new lang_string('paymentaccounts', 'payment'),
|
||||
new moodle_url("/payment/accounts.php"),
|
||||
['moodle/payment:manageaccounts', 'moodle/payment:viewpayments']));
|
@ -280,6 +280,25 @@ if ($hassiteconfig) {
|
||||
$plugin->load_settings($ADMIN, 'mediaplayers', $hassiteconfig);
|
||||
}
|
||||
|
||||
// Payment gateway plugins.
|
||||
$ADMIN->add('modules', new admin_category('paymentgateways', new lang_string('type_paygw_plural', 'plugin')));
|
||||
$temp = new admin_settingpage('managepaymentgateways', new lang_string('type_paygwmanage', 'plugin'));
|
||||
$temp->add(new \core_admin\local\settings\manage_payment_gateway_plugins());
|
||||
$temp->add(new admin_setting_description(
|
||||
'managepaymentgatewayspostfix',
|
||||
'',
|
||||
new lang_string('gotopaymentaccounts', 'payment',
|
||||
html_writer::link(new moodle_url('/payment/accounts.php'), get_string('paymentaccounts', 'payment')))
|
||||
));
|
||||
$ADMIN->add('paymentgateways', $temp);
|
||||
|
||||
$plugins = core_plugin_manager::instance()->get_plugins_of_type('paygw');
|
||||
core_collator::asort_objects_by_property($plugins, 'displayname');
|
||||
foreach ($plugins as $plugin) {
|
||||
/** @var \core\plugininfo\paygw $plugin */
|
||||
$plugin->load_settings($ADMIN, 'paymentgateways', $hassiteconfig);
|
||||
}
|
||||
|
||||
// Data format settings.
|
||||
$ADMIN->add('modules', new admin_category('dataformatsettings', new lang_string('dataformats')));
|
||||
$temp = new admin_settingpage('managedataformats', new lang_string('managedataformats'));
|
||||
|
@ -39,6 +39,7 @@ $ADMIN->add('root', new admin_category('license', new lang_string('license')));
|
||||
$ADMIN->add('root', new admin_category('location', new lang_string('location','admin')));
|
||||
$ADMIN->add('root', new admin_category('language', new lang_string('language')));
|
||||
$ADMIN->add('root', new admin_category('messaging', new lang_string('messagingcategory', 'admin')));
|
||||
$ADMIN->add('root', new admin_category('payment', new lang_string('payments', 'payment')));
|
||||
$ADMIN->add('root', new admin_category('modules', new lang_string('plugins', 'admin')));
|
||||
$ADMIN->add('root', new admin_category('security', new lang_string('security','admin')));
|
||||
$ADMIN->add('root', new admin_category('appearance', new lang_string('appearance','admin')));
|
||||
|
80
enrol/fee/classes/payment/service_provider.php
Normal file
80
enrol/fee/classes/payment/service_provider.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Payment subsystem callback implementation for enrol_fee.
|
||||
*
|
||||
* @package enrol_fee
|
||||
* @category payment
|
||||
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace enrol_fee\payment;
|
||||
|
||||
/**
|
||||
* Payment subsystem callback implementation for enrol_fee.
|
||||
*
|
||||
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class service_provider implements \core_payment\local\callback\service_provider {
|
||||
|
||||
/**
|
||||
* Callback function that returns the enrolment cost and the accountid
|
||||
* for the course that $instanceid enrolment instance belongs to.
|
||||
*
|
||||
* @param string $paymentarea
|
||||
* @param int $instanceid The enrolment instance id
|
||||
* @return \core_payment\local\entities\payable
|
||||
*/
|
||||
public static function get_payable(string $paymentarea, int $instanceid): \core_payment\local\entities\payable {
|
||||
global $DB;
|
||||
|
||||
$instance = $DB->get_record('enrol', ['enrol' => 'fee', 'id' => $instanceid], '*', MUST_EXIST);
|
||||
|
||||
return new \core_payment\local\entities\payable($instance->cost, $instance->currency, $instance->customint1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function that delivers what the user paid for to them.
|
||||
*
|
||||
* @param string $paymentarea
|
||||
* @param int $instanceid The enrolment instance id
|
||||
* @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 $instanceid, int $paymentid, int $userid): bool {
|
||||
global $DB;
|
||||
|
||||
$instance = $DB->get_record('enrol', ['enrol' => 'fee', 'id' => $instanceid], '*', MUST_EXIST);
|
||||
|
||||
$plugin = enrol_get_plugin('fee');
|
||||
|
||||
if ($instance->enrolperiod) {
|
||||
$timestart = time();
|
||||
$timeend = $timestart + $instance->enrolperiod;
|
||||
} else {
|
||||
$timestart = 0;
|
||||
$timeend = 0;
|
||||
}
|
||||
|
||||
$plugin->enrol_user($instance, $userid, $instance->roleid, $timestart, $timeend);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
430
enrol/fee/classes/plugin.php
Normal file
430
enrol/fee/classes/plugin.php
Normal file
@ -0,0 +1,430 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Fee enrolment plugin.
|
||||
*
|
||||
* This plugin allows you to set up paid courses.
|
||||
*
|
||||
* @package enrol_fee
|
||||
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fee enrolment plugin implementation.
|
||||
*
|
||||
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class enrol_fee_plugin extends enrol_plugin {
|
||||
|
||||
/**
|
||||
* Returns the list of currencies that the payment subsystem supports and therefore we can work with.
|
||||
*
|
||||
* @return array[currencycode => currencyname]
|
||||
*/
|
||||
public function get_possible_currencies(): array {
|
||||
$codes = \core_payment\helper::get_supported_currencies();
|
||||
|
||||
$currencies = [];
|
||||
foreach ($codes as $c) {
|
||||
$currencies[$c] = new lang_string($c, 'core_currencies');
|
||||
}
|
||||
|
||||
return $currencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns optional enrolment information icons.
|
||||
*
|
||||
* This is used in course list for quick overview of enrolment options.
|
||||
*
|
||||
* We are not using single instance parameter because sometimes
|
||||
* we might want to prevent icon repetition when multiple instances
|
||||
* of one type exist. One instance may also produce several icons.
|
||||
*
|
||||
* @param array $instances all enrol instances of this type in one course
|
||||
* @return array of pix_icon
|
||||
*/
|
||||
public function get_info_icons(array $instances) {
|
||||
$found = false;
|
||||
foreach ($instances as $instance) {
|
||||
if ($instance->enrolstartdate != 0 && $instance->enrolstartdate > time()) {
|
||||
continue;
|
||||
}
|
||||
if ($instance->enrolenddate != 0 && $instance->enrolenddate < time()) {
|
||||
continue;
|
||||
}
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
if ($found) {
|
||||
return array(new pix_icon('icon', get_string('pluginname', 'enrol_fee'), 'enrol_fee'));
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
public function roles_protected() {
|
||||
// Users with role assign cap may tweak the roles later.
|
||||
return false;
|
||||
}
|
||||
|
||||
public function allow_unenrol(stdClass $instance) {
|
||||
// Users with unenrol cap may unenrol other users manually - requires enrol/fee:unenrol.
|
||||
return true;
|
||||
}
|
||||
|
||||
public function allow_manage(stdClass $instance) {
|
||||
// Users with manage cap may tweak period and status - requires enrol/fee:manage.
|
||||
return true;
|
||||
}
|
||||
|
||||
public function show_enrolme_link(stdClass $instance) {
|
||||
return ($instance->status == ENROL_INSTANCE_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the user can add a new instance in this course.
|
||||
* @param int $courseid
|
||||
* @return boolean
|
||||
*/
|
||||
public function can_add_instance($courseid) {
|
||||
$context = context_course::instance($courseid, MUST_EXIST);
|
||||
|
||||
if (empty(\core_payment\helper::get_supported_currencies())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!has_capability('moodle/course:enrolconfig', $context) or !has_capability('enrol/fee:config', $context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Multiple instances supported - different cost for different roles.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* We are a good plugin and don't invent our own UI/validation code path.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function use_standard_editing_ui() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new instance of enrol plugin.
|
||||
* @param object $course
|
||||
* @param array $fields instance fields
|
||||
* @return int id of new instance, null if can not be created
|
||||
*/
|
||||
public function add_instance($course, array $fields = null) {
|
||||
if ($fields && !empty($fields['cost'])) {
|
||||
$fields['cost'] = unformat_float($fields['cost']);
|
||||
}
|
||||
return parent::add_instance($course, $fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update instance of enrol plugin.
|
||||
* @param stdClass $instance
|
||||
* @param stdClass $data modified instance fields
|
||||
* @return boolean
|
||||
*/
|
||||
public function update_instance($instance, $data) {
|
||||
if ($data) {
|
||||
$data->cost = unformat_float($data->cost);
|
||||
}
|
||||
return parent::update_instance($instance, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates course enrol form, checks if form submitted
|
||||
* and enrols user if necessary. It can also redirect.
|
||||
*
|
||||
* @param stdClass $instance
|
||||
* @return string html text, usually a form in a text box
|
||||
*/
|
||||
public function enrol_page_hook(stdClass $instance) {
|
||||
global $CFG, $USER, $OUTPUT, $PAGE, $DB;
|
||||
|
||||
ob_start();
|
||||
|
||||
if ($DB->record_exists('user_enrolments', array('userid' => $USER->id, 'enrolid' => $instance->id))) {
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
if ($instance->enrolstartdate != 0 && $instance->enrolstartdate > time()) {
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
if ($instance->enrolenddate != 0 && $instance->enrolenddate < time()) {
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
$course = $DB->get_record('course', array('id' => $instance->courseid));
|
||||
$context = context_course::instance($course->id);
|
||||
|
||||
$shortname = format_string($course->shortname, true, array('context' => $context));
|
||||
$strloginto = get_string("loginto", "", $shortname);
|
||||
$strcourses = get_string("courses");
|
||||
|
||||
// Pass $view=true to filter hidden caps if the user cannot see them.
|
||||
if ($users = get_users_by_capability($context, 'moodle/course:update', 'u.*', 'u.id ASC',
|
||||
'', '', '', '', false, true)) {
|
||||
$users = sort_by_roleassignment_authority($users, $context);
|
||||
$teacher = array_shift($users);
|
||||
} else {
|
||||
$teacher = false;
|
||||
}
|
||||
|
||||
if ( (float) $instance->cost <= 0 ) {
|
||||
$cost = (float) $this->get_config('cost');
|
||||
} else {
|
||||
$cost = (float) $instance->cost;
|
||||
}
|
||||
|
||||
if (abs($cost) < 0.01) { // No cost, other enrolment methods (instances) should be used.
|
||||
echo '<p>'.get_string('nocost', 'enrol_fee').'</p>';
|
||||
} else {
|
||||
|
||||
$data = [
|
||||
'isguestuser' => isguestuser(),
|
||||
'cost' => \core_payment\helper::get_cost_as_string($cost, $instance->currency),
|
||||
'instanceid' => $instance->id,
|
||||
'description' => get_string('purchasedescription', 'enrol_fee',
|
||||
format_string($course->fullname, true, ['context' => $context])),
|
||||
];
|
||||
echo $OUTPUT->render_from_template('enrol_fee/payment_region', $data);
|
||||
}
|
||||
|
||||
return $OUTPUT->box(ob_get_clean());
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore instance and map settings.
|
||||
*
|
||||
* @param restore_enrolments_structure_step $step
|
||||
* @param stdClass $data
|
||||
* @param stdClass $course
|
||||
* @param int $oldid
|
||||
*/
|
||||
public function restore_instance(restore_enrolments_structure_step $step, stdClass $data, $course, $oldid) {
|
||||
global $DB;
|
||||
if ($step->get_task()->get_target() == backup::TARGET_NEW_COURSE) {
|
||||
$merge = false;
|
||||
} else {
|
||||
$merge = array(
|
||||
'courseid' => $data->courseid,
|
||||
'enrol' => $this->get_name(),
|
||||
'roleid' => $data->roleid,
|
||||
'cost' => $data->cost,
|
||||
'currency' => $data->currency,
|
||||
);
|
||||
}
|
||||
if ($merge and $instances = $DB->get_records('enrol', $merge, 'id')) {
|
||||
$instance = reset($instances);
|
||||
$instanceid = $instance->id;
|
||||
} else {
|
||||
$instanceid = $this->add_instance($course, (array) $data);
|
||||
}
|
||||
$step->set_mapping('enrol', $oldid, $instanceid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore user enrolment.
|
||||
*
|
||||
* @param restore_enrolments_structure_step $step
|
||||
* @param stdClass $data
|
||||
* @param stdClass $instance
|
||||
* @param int $oldinstancestatus
|
||||
* @param int $userid
|
||||
*/
|
||||
public function restore_user_enrolment(restore_enrolments_structure_step $step, $data, $instance, $userid, $oldinstancestatus) {
|
||||
$this->enrol_user($instance, $userid, null, $data->timestart, $data->timeend, $data->status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of valid options for the status.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_status_options() {
|
||||
$options = array(ENROL_INSTANCE_ENABLED => get_string('yes'),
|
||||
ENROL_INSTANCE_DISABLED => get_string('no'));
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of valid options for the roleid.
|
||||
*
|
||||
* @param stdClass $instance
|
||||
* @param context $context
|
||||
* @return array
|
||||
*/
|
||||
protected function get_roleid_options($instance, $context) {
|
||||
if ($instance->id) {
|
||||
$roles = get_default_enrol_roles($context, $instance->roleid);
|
||||
} else {
|
||||
$roles = get_default_enrol_roles($context, $this->get_config('roleid'));
|
||||
}
|
||||
return $roles;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add elements to the edit instance form.
|
||||
*
|
||||
* @param stdClass $instance
|
||||
* @param MoodleQuickForm $mform
|
||||
* @param context $context
|
||||
* @return bool
|
||||
*/
|
||||
public function edit_instance_form($instance, MoodleQuickForm $mform, $context) {
|
||||
|
||||
$mform->addElement('text', 'name', get_string('custominstancename', 'enrol'));
|
||||
$mform->setType('name', PARAM_TEXT);
|
||||
|
||||
$options = $this->get_status_options();
|
||||
$mform->addElement('select', 'status', get_string('status', 'enrol_fee'), $options);
|
||||
$mform->setDefault('status', $this->get_config('status'));
|
||||
|
||||
$accounts = \core_payment\helper::get_payment_accounts_menu($context);
|
||||
if ($accounts) {
|
||||
$accounts = ((count($accounts) > 1) ? ['' => ''] : []) + $accounts;
|
||||
$mform->addElement('select', 'customint1', get_string('paymentaccount', 'payment'), $accounts);
|
||||
} else {
|
||||
$mform->addElement('static', 'customint1_text', get_string('paymentaccount', 'payment'),
|
||||
html_writer::span(get_string('noaccountsavilable', 'payment'), 'alert alert-danger'));
|
||||
$mform->addElement('hidden', 'customint1');
|
||||
$mform->setType('customint1', PARAM_INT);
|
||||
}
|
||||
$mform->addHelpButton('customint1', 'paymentaccount', 'enrol_fee');
|
||||
|
||||
$mform->addElement('text', 'cost', get_string('cost', 'enrol_fee'), array('size' => 4));
|
||||
$mform->setType('cost', PARAM_RAW);
|
||||
$mform->setDefault('cost', format_float($this->get_config('cost'), 2, true));
|
||||
|
||||
$supportedcurrencies = $this->get_possible_currencies();
|
||||
$mform->addElement('select', 'currency', get_string('currency', 'enrol_fee'), $supportedcurrencies);
|
||||
$mform->setDefault('currency', $this->get_config('currency'));
|
||||
|
||||
$roles = $this->get_roleid_options($instance, $context);
|
||||
$mform->addElement('select', 'roleid', get_string('assignrole', 'enrol_fee'), $roles);
|
||||
$mform->setDefault('roleid', $this->get_config('roleid'));
|
||||
|
||||
$options = array('optional' => true, 'defaultunit' => 86400);
|
||||
$mform->addElement('duration', 'enrolperiod', get_string('enrolperiod', 'enrol_fee'), $options);
|
||||
$mform->setDefault('enrolperiod', $this->get_config('enrolperiod'));
|
||||
$mform->addHelpButton('enrolperiod', 'enrolperiod', 'enrol_fee');
|
||||
|
||||
$options = array('optional' => true);
|
||||
$mform->addElement('date_time_selector', 'enrolstartdate', get_string('enrolstartdate', 'enrol_fee'), $options);
|
||||
$mform->setDefault('enrolstartdate', 0);
|
||||
$mform->addHelpButton('enrolstartdate', 'enrolstartdate', 'enrol_fee');
|
||||
|
||||
$options = array('optional' => true);
|
||||
$mform->addElement('date_time_selector', 'enrolenddate', get_string('enrolenddate', 'enrol_fee'), $options);
|
||||
$mform->setDefault('enrolenddate', 0);
|
||||
$mform->addHelpButton('enrolenddate', 'enrolenddate', 'enrol_fee');
|
||||
|
||||
if (enrol_accessing_via_instance($instance)) {
|
||||
$warningtext = get_string('instanceeditselfwarningtext', 'core_enrol');
|
||||
$mform->addElement('static', 'selfwarn', get_string('instanceeditselfwarning', 'core_enrol'), $warningtext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform custom validation of the data used to edit the instance.
|
||||
*
|
||||
* @param array $data array of ("fieldname"=>value) of submitted data
|
||||
* @param array $files array of uploaded files "element_name"=>tmp_file_path
|
||||
* @param object $instance The instance loaded from the DB
|
||||
* @param context $context The context of the instance we are editing
|
||||
* @return array of "element_name"=>"error_description" if there are errors,
|
||||
* or an empty array if everything is OK.
|
||||
* @return void
|
||||
*/
|
||||
public function edit_instance_validation($data, $files, $instance, $context) {
|
||||
$errors = array();
|
||||
|
||||
if (!empty($data['enrolenddate']) and $data['enrolenddate'] < $data['enrolstartdate']) {
|
||||
$errors['enrolenddate'] = get_string('enrolenddaterror', 'enrol_fee');
|
||||
}
|
||||
|
||||
$cost = str_replace(get_string('decsep', 'langconfig'), '.', $data['cost']);
|
||||
if (!is_numeric($cost)) {
|
||||
$errors['cost'] = get_string('costerror', 'enrol_fee');
|
||||
}
|
||||
|
||||
$validstatus = array_keys($this->get_status_options());
|
||||
$validcurrency = array_keys($this->get_possible_currencies());
|
||||
$validroles = array_keys($this->get_roleid_options($instance, $context));
|
||||
$tovalidate = array(
|
||||
'name' => PARAM_TEXT,
|
||||
'status' => $validstatus,
|
||||
'currency' => $validcurrency,
|
||||
'roleid' => $validroles,
|
||||
'enrolperiod' => PARAM_INT,
|
||||
'enrolstartdate' => PARAM_INT,
|
||||
'enrolenddate' => PARAM_INT
|
||||
);
|
||||
|
||||
$typeerrors = $this->validate_param_types($data, $tovalidate);
|
||||
$errors = array_merge($errors, $typeerrors);
|
||||
|
||||
if ($data['status'] == ENROL_INSTANCE_ENABLED &&
|
||||
(!$data['customint1']
|
||||
|| !array_key_exists($data['customint1'], \core_payment\helper::get_payment_accounts_menu($context)))) {
|
||||
$errors['status'] = 'Enrolments can not be enabled without specifying the payment account';
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute synchronisation.
|
||||
* @param progress_trace $trace
|
||||
* @return int exit code, 0 means ok
|
||||
*/
|
||||
public function sync(progress_trace $trace) {
|
||||
$this->process_expirations($trace);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is it possible to delete enrol instance via standard UI?
|
||||
*
|
||||
* @param stdClass $instance
|
||||
* @return bool
|
||||
*/
|
||||
public function can_delete_instance($instance) {
|
||||
$context = context_course::instance($instance->courseid);
|
||||
return has_capability('enrol/fee:config', $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is it possible to hide/show enrol instance via standard UI?
|
||||
*
|
||||
* @param stdClass $instance
|
||||
* @return bool
|
||||
*/
|
||||
public function can_hide_show_instance($instance) {
|
||||
$context = context_course::instance($instance->courseid);
|
||||
return has_capability('enrol/fee:config', $context);
|
||||
}
|
||||
}
|
269
enrol/fee/classes/privacy/provider.php
Normal file
269
enrol/fee/classes/privacy/provider.php
Normal file
@ -0,0 +1,269 @@
|
||||
<?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 enrol_fee.
|
||||
*
|
||||
* @package enrol_fee
|
||||
* @category privacy
|
||||
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace enrol_fee\privacy;
|
||||
|
||||
use core_privacy\local\request\approved_contextlist;
|
||||
use core_privacy\local\request\approved_userlist;
|
||||
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 for enrol_fee implementing null_provider.
|
||||
*
|
||||
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class provider implements
|
||||
\core_privacy\local\metadata\null_provider,
|
||||
\core_payment\privacy\consumer_provider
|
||||
{
|
||||
/**
|
||||
* Get the language string identifier with the component's language
|
||||
* file to explain why this plugin stores no data.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_reason(): string {
|
||||
return 'privacy:metadata';
|
||||
}
|
||||
|
||||
public static function get_contextid_for_payment(string $paymentarea, int $itemid): ?int {
|
||||
global $DB;
|
||||
|
||||
$sql = "SELECT ctx.id
|
||||
FROM {enrol} e
|
||||
JOIN {context} ctx ON (e.courseid = ctx.instanceid AND ctx.contextlevel = :contextcourse)
|
||||
WHERE e.id = :enrolid AND e.enrol = :enrolname";
|
||||
$params = [
|
||||
'contextcourse' => CONTEXT_COURSE,
|
||||
'enrolid' => $itemid,
|
||||
'enrolname' => 'fee',
|
||||
];
|
||||
$contextid = $DB->get_field_sql($sql, $params);
|
||||
|
||||
return $contextid ?: null;
|
||||
}
|
||||
|
||||
public static function get_users_in_context(userlist $userlist) {
|
||||
$context = $userlist->get_context();
|
||||
|
||||
if ($context instanceof \context_course) {
|
||||
$sql = "SELECT p.userid
|
||||
FROM {payments} p
|
||||
JOIN {enrol} e ON (p.component = :component AND p.itemid = e.id)
|
||||
WHERE e.courseid = :courseid";
|
||||
$params = [
|
||||
'component' => 'enrol_fee',
|
||||
'courseid' => $context->instanceid,
|
||||
];
|
||||
$userlist->add_from_sql('userid', $sql, $params);
|
||||
} else if ($context instanceof \context_system) {
|
||||
// If context is system, then the enrolment belongs to a deleted enrolment.
|
||||
$sql = "SELECT p.userid
|
||||
FROM {payments} p
|
||||
LEFT JOIN {enrol} e ON p.itemid = e.id
|
||||
WHERE p.component = :component AND e.id IS NULL";
|
||||
$params = [
|
||||
'component' => 'enrol_fee',
|
||||
];
|
||||
$userlist->add_from_sql('userid', $sql, $params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
$subcontext = [
|
||||
get_string('pluginname', 'enrol_fee'),
|
||||
];
|
||||
foreach ($contextlist as $context) {
|
||||
if (!$context instanceof \context_course) {
|
||||
continue;
|
||||
}
|
||||
$feeplugins = $DB->get_records('enrol', ['courseid' => $context->instanceid, 'enrol' => 'fee']);
|
||||
|
||||
foreach ($feeplugins as $feeplugin) {
|
||||
\core_payment\privacy\provider::export_payment_data_for_user_in_context(
|
||||
$context,
|
||||
$subcontext,
|
||||
$contextlist->get_user()->id,
|
||||
'enrol_fee',
|
||||
'fee',
|
||||
$feeplugin->id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array(SYSCONTEXTID, $contextlist->get_contextids())) {
|
||||
// Orphaned payments.
|
||||
$sql = "SELECT p.*
|
||||
FROM {payments} p
|
||||
LEFT JOIN {enrol} e ON p.itemid = e.id
|
||||
WHERE p.userid = :userid AND p.component = :component AND e.id IS NULL";
|
||||
$params = [
|
||||
'component' => 'enrol_fee',
|
||||
'userid' => $contextlist->get_user()->id,
|
||||
];
|
||||
|
||||
$orphanedpayments = $DB->get_recordset_sql($sql, $params);
|
||||
foreach ($orphanedpayments as $payment) {
|
||||
\core_payment\privacy\provider::export_payment_data_for_user_in_context(
|
||||
\context_system::instance(),
|
||||
$subcontext,
|
||||
$payment->userid,
|
||||
$payment->component,
|
||||
$payment->paymentarea,
|
||||
$payment->itemid
|
||||
);
|
||||
}
|
||||
$orphanedpayments->close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
if ($context instanceof \context_course) {
|
||||
$sql = "SELECT p.id
|
||||
FROM {payments} p
|
||||
JOIN {enrol} e ON (p.component = :component AND p.itemid = e.id)
|
||||
WHERE e.courseid = :courseid";
|
||||
$params = [
|
||||
'component' => 'enrol_fee',
|
||||
'courseid' => $context->instanceid,
|
||||
];
|
||||
|
||||
\core_payment\privacy\provider::delete_data_for_payment_sql($sql, $params);
|
||||
} else if ($context instanceof \context_system) {
|
||||
// If context is system, then the enrolment belongs to a deleted enrolment.
|
||||
$sql = "SELECT p.id
|
||||
FROM {payments} p
|
||||
LEFT JOIN {enrol} e ON p.itemid = e.id
|
||||
WHERE p.component = :component AND e.id IS NULL";
|
||||
$params = [
|
||||
'component' => 'enrol_fee',
|
||||
];
|
||||
|
||||
\core_payment\privacy\provider::delete_data_for_payment_sql($sql, $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;
|
||||
|
||||
if (empty($contextlist->count())) {
|
||||
return;
|
||||
}
|
||||
|
||||
$contexts = $contextlist->get_contexts();
|
||||
|
||||
$courseids = [];
|
||||
foreach ($contexts as $context) {
|
||||
if ($context instanceof \context_course) {
|
||||
$courseids[] = $context->instanceid;
|
||||
}
|
||||
}
|
||||
|
||||
[$insql, $inparams] = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED);
|
||||
|
||||
$sql = "SELECT p.id
|
||||
FROM {payments} p
|
||||
JOIN {enrol} e ON (p.component = :component AND p.itemid = e.id)
|
||||
WHERE p.userid = :userid AND e.courseid $insql";
|
||||
$params = $inparams + [
|
||||
'component' => 'enrol_fee',
|
||||
'userid' => $contextlist->get_user()->id,
|
||||
];
|
||||
|
||||
\core_payment\privacy\provider::delete_data_for_payment_sql($sql, $params);
|
||||
|
||||
if (in_array(SYSCONTEXTID, $contextlist->get_contextids())) {
|
||||
// Orphaned payments.
|
||||
$sql = "SELECT p.id
|
||||
FROM {payments} p
|
||||
LEFT JOIN {enrol} e ON p.itemid = e.id
|
||||
WHERE p.component = :component AND p.userid = :userid AND e.id IS NULL";
|
||||
$params = [
|
||||
'component' => 'enrol_fee',
|
||||
'userid' => $contextlist->get_user()->id,
|
||||
];
|
||||
|
||||
\core_payment\privacy\provider::delete_data_for_payment_sql($sql, $params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
$context = $userlist->get_context();
|
||||
|
||||
if ($context instanceof \context_course) {
|
||||
[$usersql, $userparams] = $DB->get_in_or_equal($userlist->get_userids(), SQL_PARAMS_NAMED);
|
||||
$sql = "SELECT p.id
|
||||
FROM {payments} p
|
||||
JOIN {enrol} e ON (p.component = :component AND p.itemid = e.id)
|
||||
WHERE e.courseid = :courseid AND p.userid $usersql";
|
||||
$params = $userparams + [
|
||||
'component' => 'enrol_fee',
|
||||
'courseid' => $context->instanceid,
|
||||
];
|
||||
|
||||
\core_payment\privacy\provider::delete_data_for_payment_sql($sql, $params);
|
||||
} else if ($context instanceof \context_system) {
|
||||
// Orphaned payments.
|
||||
[$usersql, $userparams] = $DB->get_in_or_equal($userlist->get_userids(), SQL_PARAMS_NAMED);
|
||||
$sql = "SELECT p.id
|
||||
FROM {payments} p
|
||||
LEFT JOIN {enrol} e ON p.itemid = e.id
|
||||
WHERE p.component = :component AND p.userid $usersql AND e.id IS NULL";
|
||||
$params = $userparams + [
|
||||
'component' => 'enrol_fee',
|
||||
];
|
||||
|
||||
\core_payment\privacy\provider::delete_data_for_payment_sql($sql, $params);
|
||||
}
|
||||
}
|
||||
}
|
61
enrol/fee/db/access.php
Normal file
61
enrol/fee/db/access.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Capabilities for fee enrolment plugin.
|
||||
*
|
||||
* @package enrol_fee
|
||||
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$capabilities = array(
|
||||
|
||||
'enrol/fee:config' => array(
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => array(
|
||||
'manager' => CAP_ALLOW,
|
||||
)
|
||||
),
|
||||
|
||||
'enrol/fee:manage' => array(
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => array(
|
||||
'manager' => CAP_ALLOW,
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
)
|
||||
),
|
||||
|
||||
'enrol/fee:unenrol' => array(
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => array(
|
||||
'manager' => CAP_ALLOW,
|
||||
)
|
||||
),
|
||||
|
||||
'enrol/fee:unenrolself' => array(
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => array(
|
||||
)
|
||||
),
|
||||
|
||||
);
|
54
enrol/fee/lang/en/enrol_fee.php
Normal file
54
enrol/fee/lang/en/enrol_fee.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Strings for component 'enrol_fee', language 'en'
|
||||
*
|
||||
* @package enrol_fee
|
||||
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['assignrole'] = 'Assign role';
|
||||
$string['cost'] = 'Enrolment fee';
|
||||
$string['costerror'] = 'The enrolment fee must be a number.';
|
||||
$string['currency'] = 'Currency';
|
||||
$string['defaultrole'] = 'Default role assignment';
|
||||
$string['defaultrole_desc'] = 'Select the role to assign to users after making a payment.';
|
||||
$string['enrolenddate'] = 'End date';
|
||||
$string['enrolenddate_help'] = 'If enabled, users can be enrolled until this date only.';
|
||||
$string['enrolenddaterror'] = 'The enrolment end date cannot be earlier than the start date.';
|
||||
$string['enrolperiod'] = 'Enrolment duration';
|
||||
$string['enrolperiod_desc'] = 'Default length of time that the enrolment is valid. If set to zero, the enrolment duration will be unlimited by default.';
|
||||
$string['enrolperiod_help'] = 'Length of time that the enrolment is valid, starting with the moment the user is enrolled. If disabled, the enrolment duration will be unlimited.';
|
||||
$string['enrolstartdate'] = 'Start date';
|
||||
$string['enrolstartdate_help'] = 'If enabled, users can only be enrolled from this date onwards.';
|
||||
$string['expiredaction'] = 'Enrolment expiry action';
|
||||
$string['expiredaction_help'] = 'Select the action to be performed when a user\'s enrolment expires. Please note that some user data and settings are deleted when a user is unenrolled.';
|
||||
$string['fee:config'] = 'Configure enrolment on payment enrol instances';
|
||||
$string['fee:manage'] = 'Manage enrolled users';
|
||||
$string['fee:unenrol'] = 'Unenrol users from course';
|
||||
$string['fee:unenrolself'] = 'Unenrol self from course';
|
||||
$string['nocost'] = 'There is no cost to enrol in this course!';
|
||||
$string['paymentaccount'] = 'Payment account';
|
||||
$string['paymentaccount_help'] = 'Enrolment fees will be paid to this account.';
|
||||
$string['pluginname'] = 'Enrolment on payment';
|
||||
$string['pluginname_desc'] = 'The enrolment on payment enrolment method allows you to set up courses requiring a payment. If the fee for any course is set to zero, then students are not asked to pay for entry. There is a site-wide fee that you set here as a default for the whole site and then a course setting that you can set for each course individually. The course fee overrides the site fee.';
|
||||
$string['privacy:metadata'] = 'The enrolment on payment enrolment plugin does not store any personal data.';
|
||||
$string['purchasedescription'] = 'Enrolment in course {$a}';
|
||||
$string['sendpaymentbutton'] = 'Select payment type';
|
||||
$string['status'] = 'Allow enrolment on payment enrolments';
|
||||
$string['status_desc'] = 'Allow users to make a payment to enrol into a course by default.';
|
25
enrol/fee/lib.php
Normal file
25
enrol/fee/lib.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Fee enrolment plugin.
|
||||
*
|
||||
* This plugin allows you to set up paid courses.
|
||||
*
|
||||
* @package enrol_fee
|
||||
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
78
enrol/fee/pix/icon.svg
Normal file
78
enrol/fee/pix/icon.svg
Normal file
@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 32.001 32.001" style="enable-background:new 0 0 32.001 32.001;" xml:space="preserve">
|
||||
<g>
|
||||
<g id="banknote">
|
||||
<path style="fill:#010002;" d="M31.415,10.586l-10-10C20.919,0.09,20.2-0.109,19.519,0.059c-0.359,0.088-0.68,0.273-0.934,0.527
|
||||
c-0.227,0.227-0.398,0.508-0.496,0.822c-0.453,1.469-1.236,2.746-2.395,3.904C14.146,6.859,12.13,8.031,9.997,9.27
|
||||
c-2.264,1.312-4.603,2.672-6.52,4.588c-1.629,1.631-2.738,3.445-3.388,5.551c-0.219,0.711-0.028,1.48,0.496,2.006l10,10
|
||||
c0.496,0.496,1.215,0.695,1.896,0.527c0.359-0.09,0.68-0.273,0.934-0.527c0.227-0.227,0.398-0.508,0.496-0.824
|
||||
c0.454-1.469,1.237-2.746,2.397-3.904c1.547-1.547,3.562-2.717,5.697-3.955c2.262-1.314,4.602-2.674,6.518-4.59
|
||||
c1.629-1.629,2.738-3.445,3.389-5.551C32.13,11.881,31.938,11.109,31.415,10.586z M12,30c-3.312-3.312-6.688-6.689-10-10
|
||||
c2.842-9.201,15.16-8.799,18-18c3.312,3.311,6.689,6.688,10.002,10C27.159,21.199,14.841,20.799,12,30z"/>
|
||||
<path style="fill:#010002;" d="M19.562,14.9c-0.326-0.273-0.654-0.459-0.984-0.551c-0.328-0.092-0.656-0.129-0.988-0.105
|
||||
c-0.328,0.025-0.664,0.1-1,0.229c-0.336,0.131-0.674,0.273-1.014,0.438c-0.537-0.617-1.074-1.227-1.611-1.793
|
||||
c0.242-0.219,0.477-0.33,0.703-0.338c0.227-0.01,0.445,0.014,0.652,0.066c0.211,0.053,0.404,0.098,0.582,0.133
|
||||
c0.18,0.035,0.336-0.004,0.473-0.119c0.145-0.125,0.225-0.287,0.236-0.482c0.01-0.197-0.064-0.389-0.229-0.576
|
||||
c-0.211-0.242-0.465-0.389-0.77-0.443c-0.301-0.053-0.609-0.049-0.93,0.021c-0.316,0.072-0.617,0.191-0.902,0.359
|
||||
s-0.514,0.34-0.684,0.508c-0.065-0.062-0.13-0.123-0.195-0.184c-0.072-0.066-0.162-0.102-0.27-0.1
|
||||
c-0.109,0-0.199,0.047-0.273,0.133c-0.072,0.084-0.105,0.182-0.092,0.285c0.01,0.107,0.053,0.189,0.127,0.252
|
||||
c0.065,0.055,0.13,0.109,0.195,0.166c-0.256,0.309-0.467,0.65-0.633,1.01c-0.168,0.361-0.268,0.719-0.305,1.066
|
||||
c-0.039,0.35-0.002,0.67,0.105,0.967c0.107,0.299,0.305,0.553,0.594,0.793c0.471,0.391,1.025,0.557,1.668,0.52
|
||||
c0.641-0.039,1.332-0.23,2.075-0.629c0.59,0.682,1.182,1.359,1.773,1.988c-0.25,0.211-0.469,0.332-0.662,0.371
|
||||
c-0.193,0.041-0.365,0.037-0.521-0.01c-0.156-0.049-0.301-0.119-0.434-0.209c-0.133-0.092-0.264-0.17-0.395-0.234
|
||||
c-0.129-0.064-0.262-0.1-0.398-0.102s-0.281,0.064-0.441,0.201c-0.164,0.143-0.246,0.309-0.246,0.496
|
||||
c0,0.186,0.086,0.375,0.254,0.566c0.17,0.191,0.391,0.352,0.658,0.479s0.569,0.207,0.901,0.229
|
||||
c0.332,0.023,0.682-0.027,1.051-0.164c0.371-0.135,0.738-0.379,1.1-0.742c0.174,0.17,0.35,0.332,0.525,0.488
|
||||
c0.074,0.064,0.164,0.096,0.273,0.088c0.105-0.004,0.197-0.053,0.27-0.141c0.074-0.09,0.105-0.189,0.094-0.293
|
||||
c-0.01-0.105-0.053-0.186-0.125-0.244c-0.176-0.141-0.352-0.289-0.527-0.445c0.299-0.367,0.539-0.754,0.717-1.137
|
||||
c0.178-0.385,0.283-0.756,0.318-1.1c0.035-0.346-0.006-0.658-0.119-0.941C20.046,15.383,19.847,15.137,19.562,14.9z
|
||||
M13.971,15.578c-0.283,0.012-0.53-0.082-0.746-0.291c-0.092-0.088-0.156-0.195-0.195-0.322c-0.041-0.127-0.055-0.266-0.039-0.418
|
||||
c0.014-0.15,0.059-0.307,0.137-0.465c0.074-0.158,0.184-0.316,0.324-0.469c0.507,0.504,1.013,1.057,1.52,1.629
|
||||
C14.588,15.453,14.254,15.566,13.971,15.578z M18.688,17.58c-0.09,0.166-0.193,0.314-0.314,0.443
|
||||
c-0.561-0.566-1.121-1.188-1.68-1.826c0.143-0.064,0.293-0.131,0.455-0.199s0.324-0.113,0.486-0.141
|
||||
c0.166-0.025,0.33-0.018,0.494,0.021c0.162,0.041,0.316,0.129,0.459,0.268c0.141,0.141,0.23,0.287,0.266,0.445
|
||||
c0.039,0.16,0.041,0.322,0.014,0.488C18.839,17.246,18.78,17.412,18.688,17.58z"/>
|
||||
<path style="fill:#010002;" d="M14.717,22.18h-0.002c-0.625,0.48-1.235,0.986-1.8,1.553c-0.543,0.543-1.034,1.115-1.461,1.699
|
||||
l-0.684,0.934l0.002,0.002c-0.125,0.195-0.104,0.457,0.066,0.627c0.195,0.195,0.514,0.195,0.71,0
|
||||
c0.03-0.031,0.054-0.064,0.074-0.1l0.639-0.875c0.396-0.541,0.854-1.074,1.361-1.58c0.561-0.561,1.081-0.994,1.714-1.475
|
||||
l-0.002-0.002c0.018-0.014,0.035-0.025,0.051-0.041c0.196-0.195,0.196-0.514,0-0.709C15.204,22.029,14.914,22.021,14.717,22.18z"
|
||||
/>
|
||||
<path style="fill:#010002;" d="M18.378,7.715c-0.523,0.523-1.09,0.994-1.678,1.443c-0.041,0.023-0.082,0.049-0.117,0.086
|
||||
c-0.197,0.197-0.197,0.518,0,0.715c0.191,0.193,0.5,0.197,0.699,0.014l0.004,0.002c0.625-0.48,1.234-0.988,1.799-1.553
|
||||
c0.543-0.543,1.033-1.113,1.461-1.697l0.684-0.938l-0.002-0.002c0.17-0.199,0.162-0.496-0.025-0.684
|
||||
c-0.197-0.197-0.516-0.197-0.713,0c-0.037,0.037-0.064,0.08-0.088,0.123l-0.664,0.91C19.341,6.678,18.884,7.209,18.378,7.715z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.7 KiB |
79
enrol/fee/settings.php
Normal file
79
enrol/fee/settings.php
Normal file
@ -0,0 +1,79 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Settings for the Fee enrolment plugin
|
||||
*
|
||||
* @package enrol_fee
|
||||
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
if ($ADMIN->fulltree) {
|
||||
|
||||
$currencies = enrol_get_plugin('fee')->get_possible_currencies();
|
||||
|
||||
if (empty($currencies)) {
|
||||
$notify = new \core\output\notification(
|
||||
get_string('nocurrencysupported', 'core_payment'),
|
||||
\core\output\notification::NOTIFY_WARNING
|
||||
);
|
||||
$settings->add(new admin_setting_heading('enrol_fee_nocurrency', '', $OUTPUT->render($notify)));
|
||||
}
|
||||
|
||||
$settings->add(new admin_setting_heading('enrol_fee_settings', '', get_string('pluginname_desc', 'enrol_fee')));
|
||||
|
||||
// Note: let's reuse the ext sync constants and strings here, internally it is very similar,
|
||||
// it describes what should happen when users are not supposed to be enrolled any more.
|
||||
$options = array(
|
||||
ENROL_EXT_REMOVED_KEEP => get_string('extremovedkeep', 'enrol'),
|
||||
ENROL_EXT_REMOVED_SUSPENDNOROLES => get_string('extremovedsuspendnoroles', 'enrol'),
|
||||
ENROL_EXT_REMOVED_UNENROL => get_string('extremovedunenrol', 'enrol'),
|
||||
);
|
||||
$settings->add(new admin_setting_configselect(
|
||||
'enrol_fee/expiredaction',
|
||||
get_string('expiredaction', 'enrol_fee'),
|
||||
get_string('expiredaction_help', 'enrol_fee'),
|
||||
ENROL_EXT_REMOVED_SUSPENDNOROLES,
|
||||
$options));
|
||||
|
||||
$settings->add(new admin_setting_heading('enrol_fee_defaults',
|
||||
get_string('enrolinstancedefaults', 'admin'), get_string('enrolinstancedefaults_desc', 'admin')));
|
||||
|
||||
$options = array(ENROL_INSTANCE_ENABLED => get_string('yes'),
|
||||
ENROL_INSTANCE_DISABLED => get_string('no'));
|
||||
$settings->add(new admin_setting_configselect('enrol_fee/status',
|
||||
get_string('status', 'enrol_fee'), get_string('status_desc', 'enrol_fee'), ENROL_INSTANCE_DISABLED, $options));
|
||||
|
||||
if (!empty($currencies)) {
|
||||
$settings->add(new admin_setting_configtext('enrol_fee/cost', get_string('cost', 'enrol_fee'), '', 0, PARAM_FLOAT, 4));
|
||||
$settings->add(new admin_setting_configselect('enrol_fee/currency', get_string('currency', 'enrol_fee'), '', '',
|
||||
$currencies));
|
||||
}
|
||||
|
||||
if (!during_initial_install()) {
|
||||
$options = get_default_enrol_roles(context_system::instance());
|
||||
$student = get_archetype_roles('student');
|
||||
$student = reset($student);
|
||||
$settings->add(new admin_setting_configselect('enrol_fee/roleid',
|
||||
get_string('defaultrole', 'enrol_fee'), get_string('defaultrole_desc', 'enrol_fee'), $student->id, $options));
|
||||
}
|
||||
|
||||
$settings->add(new admin_setting_configduration('enrol_fee/enrolperiod',
|
||||
get_string('enrolperiod', 'enrol_fee'), get_string('enrolperiod_desc', 'enrol_fee'), 0));
|
||||
}
|
76
enrol/fee/templates/payment_region.mustache
Normal file
76
enrol/fee/templates/payment_region.mustache
Normal file
@ -0,0 +1,76 @@
|
||||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template enrol_fee/payment_region
|
||||
|
||||
This template will render information about course fee along with a button for payment.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* data-component
|
||||
* data-paymentarea
|
||||
* data-itemid
|
||||
* data-cost
|
||||
* data-description
|
||||
|
||||
Context variables required for this template:
|
||||
* cost - Human readable cost string including amount and currency
|
||||
* instanceid - Id of the enrolment instance
|
||||
* description - The description for this purchase
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"cost": "$108.50",
|
||||
"instanceid": 11,
|
||||
"description": "Enrolment in course Introduction to algorithms",
|
||||
"isguestuser": false
|
||||
}
|
||||
|
||||
}}
|
||||
<div class="enrol_fee_payment_region text-center">
|
||||
{{#isguestuser}}
|
||||
<div class="mdl-align">
|
||||
<p>{{# str }} paymentrequired {{/ str}}</p>
|
||||
<p><b>{{cost}}</b></p>
|
||||
<p><a href="{{config.wwwroot}}/login/">{{# str }} loginsite {{/ str }}</a></p>
|
||||
</div>
|
||||
{{/isguestuser}}
|
||||
{{^isguestuser}}
|
||||
<p>{{# str }} paymentrequired {{/ str}}</p>
|
||||
<p><b>{{cost}}</b></p>
|
||||
<button
|
||||
class="btn btn-secondary"
|
||||
type="button"
|
||||
id="gateways-modal-trigger-{{ uniqid }}"
|
||||
data-action="core_payment/triggerPayment"
|
||||
data-component="enrol_fee"
|
||||
data-paymentarea="fee"
|
||||
data-itemid="{{instanceid}}"
|
||||
data-cost="{{cost}}"
|
||||
data-description={{# quote }}{{description}}{{/ quote }}
|
||||
>
|
||||
{{# str }} sendpaymentbutton, enrol_fee {{/ str }}
|
||||
</button>
|
||||
{{/isguestuser}}
|
||||
</div>
|
||||
{{#js}}
|
||||
require(['core_payment/gateways_modal'], function(modal) {
|
||||
modal.init();
|
||||
});
|
||||
{{/js}}
|
44
enrol/fee/tests/behat/fee.feature
Normal file
44
enrol/fee/tests/behat/fee.feature
Normal file
@ -0,0 +1,44 @@
|
||||
@enrol @enrol_fee
|
||||
Feature: Signing up for a course with a fee enrolment method
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
| manager1 | Manager | 1 | manager1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | format | summary |
|
||||
| Course 1 | C1 | topics | |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| manager1 | C1 | manager |
|
||||
And the following "core_payment > payment accounts" exist:
|
||||
| name | gateways |
|
||||
| Account1 | paypal |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Plugins > Enrolments > Manage enrol plugins" in site administration
|
||||
And I click on "Enable" "link" in the "Fee" "table_row"
|
||||
And I log out
|
||||
|
||||
@javascript
|
||||
Scenario: Student can see the payment prompt on the course enrolment page
|
||||
When I log in as "manager1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Users > Enrolment methods" in current page administration
|
||||
And I select "Fee" from the "Add method" singleselect
|
||||
And I set the following fields to these values:
|
||||
| Payment account | Account1 |
|
||||
| Enrolment fee | 123.45 |
|
||||
| Currency | Euro |
|
||||
And I press "Add method"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on course index
|
||||
And I follow "Course 1"
|
||||
Then I should see "This course requires a payment for entry."
|
||||
And I should see "123.45"
|
||||
And I press "Select payment type"
|
||||
And I should see "PayPal" in the "Select payment type" "dialogue"
|
||||
And I click on "Cancel" "button" in the "Select payment type" "dialogue"
|
29
enrol/fee/version.php
Normal file
29
enrol/fee/version.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Fee enrolment plugin version specification.
|
||||
*
|
||||
* @package enrol_fee
|
||||
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2021052500; // Requires this Moodle version.
|
||||
$plugin->component = 'enrol_fee'; // Full name of the plugin (used for diagnostics).
|
@ -32,6 +32,7 @@ $string['iso6392'] = 'eng';
|
||||
$string['labelsep'] = ': ';
|
||||
$string['listsep'] = ',';
|
||||
$string['locale'] = 'en_AU.UTF-8';
|
||||
$string['localecldr'] = 'en-AU';
|
||||
$string['localewin'] = 'English_Australia.1252';
|
||||
$string['localewincharset'] = '';
|
||||
$string['oldcharset'] = 'ISO-8859-1';
|
||||
|
@ -1126,6 +1126,7 @@ $string['ip_address'] = 'IP address';
|
||||
$string['jump'] = 'Jump';
|
||||
$string['jumpto'] = 'Jump to...';
|
||||
$string['keep'] = 'Keep';
|
||||
$string['labelvalue'] = '{$a->label}: {$a->value}';
|
||||
$string['langltr'] = 'Language direction left-to-right';
|
||||
$string['langrtl'] = 'Language direction right-to-left';
|
||||
$string['language'] = 'Language';
|
||||
|
66
lang/en/payment.php
Normal file
66
lang/en/payment.php
Normal 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/>.
|
||||
|
||||
/**
|
||||
* Strings for component 'payment', language 'en'
|
||||
*
|
||||
* @package core_payment
|
||||
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['accountarchived'] = 'Archived';
|
||||
$string['accountdeleteconfirm'] = 'If this account has previous payments, it will be archived, otherwise its configuration data will be permanently deleted. Are you sure you want to continue?';
|
||||
$string['accountconfignote'] = 'Payment gateways for this account will be configured separately';
|
||||
$string['accountidnumber'] = 'ID number';
|
||||
$string['accountidnumber_help'] = 'The ID number is only used when matching the account against external systems and is not displayed anywhere on the site. If the account has an official code name it may be entered, otherwise the field can be left blank.';
|
||||
$string['accountname'] = 'Account name';
|
||||
$string['accountname_help'] = 'How this account will be identified for teachers or managers who set up payments (for example in the course enrolment plugin)';
|
||||
$string['accountnotavailable'] = 'Not available';
|
||||
$string['paymentaccountsexplained'] = 'Create one or multiple payment accounts for this site. Each account includes configuration for available payment gateways. The person who configures payments on the site (for example, payment for the course enrolment) will be able to chose from the available accounts.';
|
||||
$string['createaccount'] = 'Create payment account';
|
||||
$string['deleteorarchive'] = 'Delete or archive';
|
||||
$string['eventaccountcreated'] = 'Payment account created';
|
||||
$string['eventaccountdeleted'] = 'Payment account deleted';
|
||||
$string['eventaccountupdated'] = 'Payment account updated';
|
||||
$string['feeincludesurcharge'] = '{$a->fee} (includes {$a->surcharge}% surcharge for using this payment type)';
|
||||
$string['gatewaycannotbeenabled'] = 'The payment gateway cannot be enabled because the configuration is incomplete.';
|
||||
$string['gatewaydisabled'] = 'Disabled';
|
||||
$string['gatewayenabled'] = 'Enabled';
|
||||
$string['gatewaynotfound'] = 'Gateway not found';
|
||||
$string['gotomanageplugins'] = 'Enable and disable payment gateways and set surcharges via {$a}.';
|
||||
$string['gotopaymentaccounts'] = 'You can create multiple payment accounts using any of these gateways on the {$a} page';
|
||||
$string['hidearchived'] = 'Hide archived';
|
||||
$string['noaccountsavilable'] = 'No payment accounts are available.';
|
||||
$string['nocurrencysupported'] = 'No payment in any currency is supported. Please make sure that at least one payment gateway is enabled.';
|
||||
$string['nogateway'] = 'There is no payment gateway that can be used.';
|
||||
$string['nogatewayselected'] = 'You first need to select a payment gateway.';
|
||||
$string['payments'] = 'Payments';
|
||||
$string['paymentaccount'] = 'Payment account';
|
||||
$string['paymentaccounts'] = 'Payment accounts';
|
||||
$string['privacy:metadata:database:payments'] = 'Information about the payments.';
|
||||
$string['privacy:metadata:database:payments:amount'] = 'The amount for the payment.';
|
||||
$string['privacy:metadata:database:payments:currency'] = 'The currency of the payment.';
|
||||
$string['privacy:metadata:database:payments:gateway'] = 'The payment gateway that is used for the payment.';
|
||||
$string['privacy:metadata:database:payments:timecreated'] = 'The time when the payment was made.';
|
||||
$string['privacy:metadata:database:payments:timemodified'] = 'The time when the payment record was last updated.';
|
||||
$string['privacy:metadata:database:payments:userid'] = 'The user who made the payment.';
|
||||
$string['restoreaccount'] = 'Restore';
|
||||
$string['selectpaymenttype'] = 'Select payment type';
|
||||
$string['showarchived'] = 'Show archived';
|
||||
$string['supportedcurrencies'] = 'Supported currencies';
|
||||
$string['surcharge'] = 'Surcharge (percentage)';
|
||||
$string['surcharge_desc'] = 'The surcharge is an additional percentage charged to users who choose to pay using this payment gateway.';
|
@ -165,6 +165,9 @@ $string['type_mnetservice'] = 'MNet service';
|
||||
$string['type_mnetservice_plural'] = 'MNet services';
|
||||
$string['type_mod'] = 'Activity module';
|
||||
$string['type_mod_plural'] = 'Activity modules';
|
||||
$string['type_paygwmanage'] = 'Manage payment gateways';
|
||||
$string['type_paygw'] = 'Payment gateway';
|
||||
$string['type_paygw_plural'] = 'Payment gateways';
|
||||
$string['type_plagiarism'] = 'Plagiarism plugin';
|
||||
$string['type_plagiarism_plural'] = 'Plagiarism plugins';
|
||||
$string['type_portfolio'] = 'Portfolio';
|
||||
|
2
lib/amd/build/modal.min.js
vendored
2
lib/amd/build/modal.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
lib/amd/build/modal_events.min.js
vendored
2
lib/amd/build/modal_events.min.js
vendored
@ -1,2 +1,2 @@
|
||||
define ("core/modal_events",[],function(){return{shown:"modal:shown",hidden:"modal:hidden",destroyed:"modal:destroyed",bodyRendered:"modal:bodyRendered",save:"modal-save-cancel:save",cancel:"modal-save-cancel:cancel"}});
|
||||
define ("core/modal_events",[],function(){return{shown:"modal:shown",hidden:"modal:hidden",destroyed:"modal:destroyed",bodyRendered:"modal:bodyRendered",outsideClick:"modal:outsideClick",save:"modal-save-cancel:save",cancel:"modal-save-cancel:cancel"}});
|
||||
//# sourceMappingURL=modal_events.min.js.map
|
||||
|
@ -1 +1 @@
|
||||
{"version":3,"sources":["../src/modal_events.js"],"names":["define","shown","hidden","destroyed","bodyRendered","save","cancel"],"mappings":"AAwBAA,OAAM,qBAAC,EAAD,CAAK,UAAW,CAClB,MAAO,CAEHC,KAAK,CAAE,aAFJ,CAGHC,MAAM,CAAE,cAHL,CAIHC,SAAS,CAAE,iBAJR,CAKHC,YAAY,CAAE,oBALX,CAOHC,IAAI,CAAE,wBAPH,CAQHC,MAAM,CAAE,0BARL,CAUV,CAXK,CAAN","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Contain the events a modal can fire.\n *\n * @module core/modal_events\n * @class modal_events\n * @package core\n * @copyright 2016 Ryan Wyllie <ryan@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([], function() {\n return {\n // Default events.\n shown: 'modal:shown',\n hidden: 'modal:hidden',\n destroyed: 'modal:destroyed',\n bodyRendered: 'modal:bodyRendered',\n // ModalSaveCancel events.\n save: 'modal-save-cancel:save',\n cancel: 'modal-save-cancel:cancel',\n };\n});\n"],"file":"modal_events.min.js"}
|
||||
{"version":3,"sources":["../src/modal_events.js"],"names":["define","shown","hidden","destroyed","bodyRendered","outsideClick","save","cancel"],"mappings":"AAwBAA,OAAM,qBAAC,EAAD,CAAK,UAAW,CAClB,MAAO,CAEHC,KAAK,CAAE,aAFJ,CAGHC,MAAM,CAAE,cAHL,CAIHC,SAAS,CAAE,iBAJR,CAKHC,YAAY,CAAE,oBALX,CAMHC,YAAY,CAAE,oBANX,CAQHC,IAAI,CAAE,wBARH,CASHC,MAAM,CAAE,0BATL,CAWV,CAZK,CAAN","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Contain the events a modal can fire.\n *\n * @module core/modal_events\n * @class modal_events\n * @package core\n * @copyright 2016 Ryan Wyllie <ryan@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([], function() {\n return {\n // Default events.\n shown: 'modal:shown',\n hidden: 'modal:hidden',\n destroyed: 'modal:destroyed',\n bodyRendered: 'modal:bodyRendered',\n outsideClick: 'modal:outsideClick',\n // ModalSaveCancel events.\n save: 'modal-save-cancel:save',\n cancel: 'modal-save-cancel:cancel',\n };\n});\n"],"file":"modal_events.min.js"}
|
@ -780,7 +780,12 @@ define([
|
||||
// So, we check if we can still find the container element or not. If not, then the DOM tree is changed.
|
||||
// It's best not to hide the modal in that case.
|
||||
if ($(e.target).closest(SELECTORS.CONTAINER).length) {
|
||||
this.hideIfNotForm();
|
||||
var outsideClickEvent = $.Event(ModalEvents.outsideClick);
|
||||
this.getRoot().trigger(outsideClickEvent, this);
|
||||
|
||||
if (!outsideClickEvent.isDefaultPrevented()) {
|
||||
this.hideIfNotForm();
|
||||
}
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
|
@ -29,6 +29,7 @@ define([], function() {
|
||||
hidden: 'modal:hidden',
|
||||
destroyed: 'modal:destroyed',
|
||||
bodyRendered: 'modal:bodyRendered',
|
||||
outsideClick: 'modal:outsideClick',
|
||||
// ModalSaveCancel events.
|
||||
save: 'modal-save-cancel:save',
|
||||
cancel: 'modal-save-cancel:cancel',
|
||||
|
@ -268,7 +268,7 @@ abstract class persistent extends moodleform {
|
||||
/**
|
||||
* Return the persistent object associated with this form instance.
|
||||
*
|
||||
* @return core\persistent
|
||||
* @return \core\persistent
|
||||
*/
|
||||
final protected function get_persistent() {
|
||||
return $this->persistent;
|
||||
|
@ -1853,7 +1853,7 @@ class core_plugin_manager {
|
||||
'enrol' => array(
|
||||
'category', 'cohort', 'database', 'flatfile',
|
||||
'guest', 'imsenterprise', 'ldap', 'lti', 'manual', 'meta', 'mnet',
|
||||
'paypal', 'self'
|
||||
'paypal', 'self', 'fee',
|
||||
),
|
||||
|
||||
'filter' => array(
|
||||
@ -1923,6 +1923,10 @@ class core_plugin_manager {
|
||||
'quiz', 'resource', 'scorm', 'survey', 'url', 'wiki', 'workshop'
|
||||
),
|
||||
|
||||
'paygw' => [
|
||||
'paypal',
|
||||
],
|
||||
|
||||
'plagiarism' => array(
|
||||
),
|
||||
|
||||
|
143
lib/classes/plugininfo/paygw.php
Normal file
143
lib/classes/plugininfo/paygw.php
Normal file
@ -0,0 +1,143 @@
|
||||
<?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 subplugin info 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\plugininfo;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Payment gateway subplugin info class.
|
||||
*
|
||||
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class paygw extends base {
|
||||
public function is_uninstall_allowed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_settings_section_name() {
|
||||
return 'paymentgateway' . $this->name;
|
||||
}
|
||||
|
||||
public function load_settings(\part_of_admin_tree $adminroot, $parentnodename, $hassiteconfig) {
|
||||
global $CFG, $USER, $DB, $OUTPUT, $PAGE; // In case settings.php wants to refer to them.
|
||||
$ADMIN = $adminroot; // May be used in settings.php.
|
||||
$plugininfo = $this; // Also can be used inside settings.php.
|
||||
|
||||
if (!$this->is_installed_and_upgraded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$hassiteconfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
$section = $this->get_settings_section_name();
|
||||
|
||||
$settings = null;
|
||||
if (file_exists($this->full_path('settings.php'))) {
|
||||
$settings = new \admin_settingpage($section, $this->displayname, 'moodle/site:config', $this->is_enabled() === false);
|
||||
include($this->full_path('settings.php')); // This may also set $settings to null.
|
||||
}
|
||||
if ($settings) {
|
||||
$ADMIN->add($parentnodename, $settings);
|
||||
}
|
||||
}
|
||||
|
||||
public static function get_manage_url() {
|
||||
return new \moodle_url('/admin/settings.php', array('section' => 'managepaymentgateways'));
|
||||
}
|
||||
|
||||
public static function get_enabled_plugins() {
|
||||
global $CFG;
|
||||
|
||||
$order = (!empty($CFG->paygw_plugins_sortorder)) ? explode(',', $CFG->paygw_plugins_sortorder) : [];
|
||||
if ($order) {
|
||||
$plugins = \core_plugin_manager::instance()->get_installed_plugins('paygw');
|
||||
$order = array_intersect($order, array_keys($plugins));
|
||||
}
|
||||
|
||||
return array_combine($order, $order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current plugin as enabled or disabled
|
||||
* When enabling tries to guess the sortorder based on default rank returned by the plugin.
|
||||
*
|
||||
* @param bool $newstate
|
||||
*/
|
||||
public function set_enabled(bool $newstate = true) {
|
||||
$enabled = self::get_enabled_plugins();
|
||||
if (array_key_exists($this->name, $enabled) == $newstate) {
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
if ($newstate) {
|
||||
// Enable gateway plugin.
|
||||
$plugins = \core_plugin_manager::instance()->get_plugins_of_type('paygw');
|
||||
if (!array_key_exists($this->name, $plugins)) {
|
||||
// Can not be enabled.
|
||||
return;
|
||||
}
|
||||
$enabled[$this->name] = $this->name;
|
||||
self::set_enabled_plugins($enabled);
|
||||
} else {
|
||||
// Disable gateway plugin.
|
||||
unset($enabled[$this->name]);
|
||||
self::set_enabled_plugins($enabled);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the list of enabled payment gateways in the specified sort order
|
||||
* To be used when changing settings or in unit tests.
|
||||
*
|
||||
* @param string|array $list list of plugin names without frankenstyle prefix - comma-separated string or an array
|
||||
*/
|
||||
public static function set_enabled_plugins($list) {
|
||||
if (empty($list)) {
|
||||
$list = [];
|
||||
} else if (!is_array($list)) {
|
||||
$list = explode(',', $list);
|
||||
}
|
||||
if ($list) {
|
||||
$plugins = \core_plugin_manager::instance()->get_installed_plugins('paygw');
|
||||
$list = array_intersect($list, array_keys($plugins));
|
||||
}
|
||||
set_config('paygw_plugins_sortorder', join(',', $list));
|
||||
\core_plugin_manager::reset_caches();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function get_supported_currencies(): array {
|
||||
$classname = '\paygw_'.$this->name.'\gateway';
|
||||
|
||||
return $classname::get_supported_currencies();
|
||||
}
|
||||
}
|
@ -38,7 +38,8 @@
|
||||
"contenttype": "contentbank\/contenttype",
|
||||
"theme": "theme",
|
||||
"local": "local",
|
||||
"h5plib": "h5p\/h5plib"
|
||||
"h5plib": "h5p\/h5plib",
|
||||
"paygw": "payment\/gateway"
|
||||
},
|
||||
"subsystems": {
|
||||
"access": null,
|
||||
@ -94,6 +95,7 @@
|
||||
"my": "my",
|
||||
"notes": "notes",
|
||||
"pagetype": null,
|
||||
"payment" : "payment",
|
||||
"pix": null,
|
||||
"plagiarism": "plagiarism",
|
||||
"plugin": null,
|
||||
|
@ -2596,6 +2596,22 @@ $capabilities = array(
|
||||
'archetypes' => array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'manager' => CAP_ALLOW
|
||||
)
|
||||
),
|
||||
],
|
||||
|
||||
// Allow to manage payment accounts.
|
||||
'moodle/payment:manageaccounts' => [
|
||||
'captype' => 'write',
|
||||
'riskbitmask' => RISK_PERSONAL | RISK_CONFIG | RISK_DATALOSS,
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => [],
|
||||
],
|
||||
|
||||
// Allow to view payments.
|
||||
'moodle/payment:viewpayments' => [
|
||||
'captype' => 'read',
|
||||
'riskbitmask' => RISK_PERSONAL,
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => [],
|
||||
],
|
||||
);
|
||||
|
54
lib/db/install.xml
Normal file → Executable file
54
lib/db/install.xml
Normal file → Executable file
@ -4289,6 +4289,60 @@
|
||||
<INDEX NAME="instance" UNIQUE="false" FIELDS="contextid, contenttype, instanceid"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="payment_accounts" COMMENT="Payment accounts">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="idnumber" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="enabled" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="archived" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="payment_gateways" COMMENT="Configuration for one gateway for one payment account">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="accountid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="gateway" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="enabled" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
|
||||
<FIELD NAME="config" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
<KEY NAME="accountid" TYPE="foreign" FIELDS="accountid" REFTABLE="payment_accounts" REFFIELDS="id"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="payments" COMMENT="Stores information about payments">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="component" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false" COMMENT="The plugin this payment belongs to."/>
|
||||
<FIELD NAME="paymentarea" TYPE="char" LENGTH="50" NOTNULL="true" SEQUENCE="false" COMMENT="The name of payable area"/>
|
||||
<FIELD NAME="itemid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="amount" TYPE="char" LENGTH="20" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="currency" TYPE="char" LENGTH="3" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="accountid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="gateway" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
<KEY NAME="userid" TYPE="foreign" FIELDS="userid" REFTABLE="user" REFFIELDS="id"/>
|
||||
<KEY NAME="accountid" TYPE="foreign" FIELDS="accountid" REFTABLE="payment_accounts" REFFIELDS="id"/>
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="gateway" UNIQUE="false" FIELDS="gateway"/>
|
||||
<INDEX NAME="component-paymentarea-itemid" UNIQUE="false" FIELDS="component, paymentarea, itemid"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="infected_files" COMMENT="Table to store infected file details.">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
|
@ -2720,6 +2720,13 @@ $functions = array(
|
||||
'ajax' => 'true',
|
||||
'capabilities' => '',
|
||||
],
|
||||
'core_payment_get_available_gateways' => [
|
||||
'classname' => 'core_payment\external\get_available_gateways',
|
||||
'methodname' => 'execute',
|
||||
'description' => 'Get the list of payment gateways that support the given component/area',
|
||||
'type' => 'read',
|
||||
'ajax' => true,
|
||||
],
|
||||
);
|
||||
|
||||
$services = array(
|
||||
|
@ -2911,10 +2911,87 @@ function xmldb_main_upgrade($oldversion) {
|
||||
}
|
||||
|
||||
$dbman->drop_field($table, $field);
|
||||
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2021052500.33);
|
||||
}
|
||||
}
|
||||
|
||||
if ($oldversion < 2021052500.33) {
|
||||
// Define table payment_accounts to be created.
|
||||
$table = new xmldb_table('payment_accounts');
|
||||
|
||||
// Adding fields to table payment_accounts.
|
||||
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
|
||||
$table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('idnumber', XMLDB_TYPE_CHAR, '100', null, null, null, null);
|
||||
$table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('enabled', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0');
|
||||
$table->add_field('archived', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0');
|
||||
$table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
|
||||
$table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
|
||||
|
||||
// Adding keys to table payment_accounts.
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
|
||||
|
||||
// Conditionally launch create table for payment_accounts.
|
||||
if (!$dbman->table_exists($table)) {
|
||||
$dbman->create_table($table);
|
||||
}
|
||||
|
||||
// Define table payment_gateways to be created.
|
||||
$table = new xmldb_table('payment_gateways');
|
||||
|
||||
// Adding fields to table payment_gateways.
|
||||
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
|
||||
$table->add_field('accountid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('gateway', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('enabled', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1');
|
||||
$table->add_field('config', XMLDB_TYPE_TEXT, null, null, null, null, null);
|
||||
$table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
|
||||
// Adding keys to table payment_gateways.
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
|
||||
$table->add_key('accountid', XMLDB_KEY_FOREIGN, ['accountid'], 'payment_accounts', ['id']);
|
||||
|
||||
// Conditionally launch create table for payment_gateways.
|
||||
if (!$dbman->table_exists($table)) {
|
||||
$dbman->create_table($table);
|
||||
}
|
||||
|
||||
// Define table payments to be created.
|
||||
$table = new xmldb_table('payments');
|
||||
|
||||
// Adding fields to table payments.
|
||||
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
|
||||
$table->add_field('component', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('paymentarea', XMLDB_TYPE_CHAR, '50', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('itemid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('amount', XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('currency', XMLDB_TYPE_CHAR, '3', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('accountid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('gateway', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
|
||||
$table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
|
||||
|
||||
// Adding keys to table payments.
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
|
||||
$table->add_key('userid', XMLDB_KEY_FOREIGN, ['userid'], 'user', ['id']);
|
||||
$table->add_key('accountid', XMLDB_KEY_FOREIGN, ['accountid'], 'payment_accounts', ['id']);
|
||||
|
||||
// Adding indexes to table payments.
|
||||
$table->add_index('gateway', XMLDB_INDEX_NOTUNIQUE, ['gateway']);
|
||||
$table->add_index('component-paymentarea-itemid', XMLDB_INDEX_NOTUNIQUE, ['component', 'paymentarea', 'itemid']);
|
||||
|
||||
// Conditionally launch create table for payments.
|
||||
if (!$dbman->table_exists($table)) {
|
||||
$dbman->create_table($table);
|
||||
}
|
||||
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2021052500.33);
|
||||
upgrade_main_savepoint(true, 2021052500.36);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -36,7 +36,7 @@ class core_component_testcase extends advanced_testcase {
|
||||
* this is defined here to annoy devs that try to add more without any thinking,
|
||||
* always verify that it does not collide with any existing add-on modules and subplugins!!!
|
||||
*/
|
||||
const SUBSYSTEMCOUNT = 71;
|
||||
const SUBSYSTEMCOUNT = 72;
|
||||
|
||||
public function setUp(): void {
|
||||
$psr0namespaces = new ReflectionProperty('core_component', 'psr0namespaces');
|
||||
|
97
payment/accounts.php
Normal file
97
payment/accounts.php
Normal file
@ -0,0 +1,97 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Management of payment accounts
|
||||
*
|
||||
* @package core_payment
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
$showarchived = optional_param('showarchived', false, PARAM_BOOL);
|
||||
|
||||
admin_externalpage_setup('paymentaccounts');
|
||||
$PAGE->set_heading(get_string('paymentaccounts', 'payment'));
|
||||
|
||||
$enabledplugins = \core\plugininfo\paygw::get_enabled_plugins();
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
$accounts = \core_payment\helper::get_payment_accounts_to_manage(context_system::instance(), $showarchived);
|
||||
$table = new html_table();
|
||||
$table->head = [get_string('accountname', 'payment'), get_string('type_paygw_plural', 'plugin'), ''];
|
||||
$table->colclasses = ['', '', 'mdl-right'];
|
||||
$table->data = [];
|
||||
foreach ($accounts as $account) {
|
||||
$gateways = [];
|
||||
$canmanage = has_capability('moodle/payment:manageaccounts', $account->get_context());
|
||||
foreach ($account->get_gateways() as $gateway) {
|
||||
$status = $gateway->get('enabled') ? $OUTPUT->pix_icon('i/valid', get_string('gatewayenabled', 'payment')) :
|
||||
$OUTPUT->pix_icon('i/invalid', get_string('gatewaydisabled', 'payment'));
|
||||
$gateways[] = $status .
|
||||
($canmanage ? html_writer::link($gateway->get_edit_url(), $gateway->get_display_name()) : $gateway->get_display_name());
|
||||
}
|
||||
$name = $account->get_formatted_name();
|
||||
if (!$account->is_available()) {
|
||||
$name .= ' ' . html_writer::span(get_string('accountnotavailable', 'payment'), 'badge badge-warning');
|
||||
}
|
||||
if ($account->get('archived')) {
|
||||
$name .= ' ' . html_writer::span(get_string('accountarchived', 'payment'), 'badge badge-secondary');
|
||||
}
|
||||
|
||||
$menu = new action_menu();
|
||||
$menu->set_alignment(action_menu::TL, action_menu::BL);
|
||||
$menu->set_menu_trigger(get_string('edit'));
|
||||
if ($canmanage) {
|
||||
$menu->add(new action_menu_link_secondary($account->get_edit_url(), null, get_string('edit')));
|
||||
if (!$account->get('archived')) {
|
||||
$deleteurl = $account->get_edit_url(['delete' => 1, 'sesskey' => sesskey()]);
|
||||
$menu->add(new action_menu_link_secondary($deleteurl, null, get_string('deleteorarchive', 'payment'),
|
||||
['data-action' => 'delete']));
|
||||
} else {
|
||||
$restoreurl = $account->get_edit_url(['restore' => 1, 'sesskey' => sesskey()]);
|
||||
$menu->add(new action_menu_link_secondary($restoreurl, null, get_string('restoreaccount', 'payment')));
|
||||
}
|
||||
}
|
||||
|
||||
$table->data[] = [$name, join(', ', $gateways), $OUTPUT->render($menu)];
|
||||
}
|
||||
|
||||
echo html_writer::div(get_string('paymentaccountsexplained', 'payment'), 'pb-2');
|
||||
|
||||
if (has_capability('moodle/site:config', context_system::instance())) {
|
||||
// For administrators add a link to "Manage payment gateways" page.
|
||||
$link = html_writer::link(new moodle_url('/admin/settings.php', ['section' => 'managepaymentgateways']),
|
||||
get_string('type_paygwmanage', 'plugin'));
|
||||
$text = get_string('gotomanageplugins', 'payment', $link);
|
||||
echo html_writer::div($text, 'pb-2');
|
||||
}
|
||||
|
||||
echo html_writer::table($table);
|
||||
|
||||
$PAGE->requires->event_handler('[data-action=delete]', 'click', 'M.util.show_confirm_dialog',
|
||||
array('message' => get_string('accountdeleteconfirm', 'payment')));
|
||||
|
||||
echo html_writer::div(html_writer::link(new moodle_url($PAGE->url, ['showarchived' => !$showarchived]),
|
||||
$showarchived ? get_string('hidearchived', 'payment') : get_string('showarchived', 'payment')), 'mdl-right');
|
||||
|
||||
echo $OUTPUT->single_button(new moodle_url('/payment/manage_account.php'), get_string('createaccount', 'payment'), 'get');
|
||||
|
||||
echo $OUTPUT->footer();
|
2
payment/amd/build/events.min.js
vendored
Normal file
2
payment/amd/build/events.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
define ("core_payment/events",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;a.default={proceed:"core_payment-modal_gateways:proceed"};return a.default});
|
||||
//# sourceMappingURL=events.min.js.map
|
1
payment/amd/build/events.min.js.map
Normal file
1
payment/amd/build/events.min.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sources":["../src/events.js"],"names":["proceed"],"mappings":"+IAwBe,CACXA,OAAO,CAAE,qCADE,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Contain the events the payment modal can fire.\n *\n * @module core_payment/events\n * @package core_payment\n * @copyright 2020 Shamim Rezaie <shamim@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport default {\n proceed: 'core_payment-modal_gateways:proceed',\n};\n"],"file":"events.min.js"}
|
2
payment/amd/build/gateways_modal.min.js
vendored
Normal file
2
payment/amd/build/gateways_modal.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
define ("core_payment/gateways_modal",["exports","core/modal_factory","core/templates","core/str","./repository","./selectors","core/modal_events","core_payment/events","core/toast","core/notification","./modal_gateways"],function(a,b,c,d,e,f,g,h,i,j,k){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=l(b);c=l(c);f=l(f);g=l(g);h=l(h);j=l(j);k=l(k);var o="undefined"!=typeof window?window:"undefined"!=typeof self?self:"undefined"!=typeof global?global:{};function l(a){return a&&a.__esModule?a:{default:a}}function m(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function n(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){m(h,d,e,f,g,"next",a)}function g(a){m(h,d,e,f,g,"throw",a)}f(void 0)})}}var p=function(){document.addEventListener("click",function(a){var b=a.target.closest("[data-action=\"core_payment/triggerPayment\"]");if(b){a.preventDefault();q(b,{focusOnClose:a.target})}})},q=function(){var a=n(regeneratorRuntime.mark(function a(l){var m,n,o,p,q,u,v,w,x,y,z=arguments;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:m=1<z.length&&z[1]!==void 0?z[1]:{},n=m.focusOnClose,o=void 0===n?null:n;a.t0=b.default;a.t1=k.default.TYPE;a.next=5;return(0,d.get_string)("selectpaymenttype","core_payment");case 5:a.t2=a.sent;a.next=8;return c.default.render("core_payment/gateways_modal",{});case 8:a.t3=a.sent;a.t4={type:a.t1,title:a.t2,body:a.t3};a.next=12;return a.t0.create.call(a.t0,a.t4);case 12:p=a.sent;q=p.getRoot()[0];(0,i.addToastRegion)(q);p.show();p.getRoot().on(g.default.hidden,function(){p.destroy();try{o.focus()}catch(a){}});p.getRoot().on(h.default.proceed,function(a){var b=(q.querySelector(f.default.values.gateway)||{value:""}).value;if(b){t(b,l.dataset.component,l.dataset.paymentarea,l.dataset.itemid,l.dataset.description).then(function(a){p.hide();j.default.addNotification({message:a,type:"success"});location.reload();return a}).catch(function(a){return j.default.alert("",a)})}else{(0,d.get_string)("nogatewayselected","core_payment").then(function(a){return(0,i.add)(a)}).catch()}a.preventDefault()});q.addEventListener("change",function(a){if(a.target.matches(f.default.elements.gateways)){s(q,l.dataset.cost)}});a.next=21;return(0,e.getAvailableGateways)(l.dataset.component,l.dataset.paymentarea,l.dataset.itemid);case 21:u=a.sent;v={gateways:u};a.next=25;return c.default.renderForPromise("core_payment/gateways",v);case 25:w=a.sent;x=w.html;y=w.js;c.default.replaceNodeContents(q.querySelector(f.default.regions.gatewaysContainer),x,y);r(q);a.next=32;return s(q,l.dataset.cost);case 32:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}(),r=function(a){var b=a.querySelectorAll(f.default.elements.gateways);if(1==b.length){b[0].checked=!0}},s=function(){var a=n(regeneratorRuntime.mark(function a(b){var d,e,g,h,i,j,k,l=arguments;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:d=1<l.length&&l[1]!==void 0?l[1]:"";e=b.querySelector(f.default.values.gateway);g=parseInt((e||{dataset:{surcharge:0}}).dataset.surcharge);h=(e||{dataset:{cost:d}}).dataset.cost;a.next=6;return c.default.renderForPromise("core_payment/fee_breakdown",{fee:h,surcharge:g});case 6:i=a.sent;j=i.html;k=i.js;c.default.replaceNodeContents(b.querySelector(f.default.regions.costContainer),j,k);case 10:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}(),t=function(){var a=n(regeneratorRuntime.mark(function a(b,c,d,e,f){var g;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:a.next=2;return"function"==typeof o.define&&o.define.amd?new Promise(function(a,c){o.require(["paygw_".concat(b,"/gateways_modal")],a,c)}):"undefined"!=typeof module&&module.exports&&"undefined"!=typeof require||"undefined"!=typeof module&&module.component&&o.require&&"component"===o.require.loader?Promise.resolve(require(("paygw_".concat(b,"/gateways_modal")))):Promise.resolve(o["paygw_".concat(b,"/gateways_modal")]);case 2:g=a.sent;return a.abrupt("return",g.process(c,d,e,f));case 4:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}(),u=function(){if(!u.initialised){u.initialised=!0;p()}};a.init=u;u.initialised=!1});
|
||||
//# sourceMappingURL=gateways_modal.min.js.map
|
1
payment/amd/build/gateways_modal.min.js.map
Normal file
1
payment/amd/build/gateways_modal.min.js.map
Normal file
File diff suppressed because one or more lines are too long
2
payment/amd/build/modal_gateways.min.js
vendored
Normal file
2
payment/amd/build/modal_gateways.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
define ("core_payment/modal_gateways",["exports","jquery","core/custom_interaction_events","core/modal","core/modal_events","core_payment/events","core/modal_registry"],function(a,b,c,d,f,g,h){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;b=i(b);c=i(c);d=i(d);f=i(f);g=i(g);h=i(h);function i(a){return a&&a.__esModule?a:{default:a}}function j(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){j=function(a){return typeof a}}else{j=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return j(a)}function k(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function l(a,b){for(var c=0,d;c<b.length;c++){d=b[c];d.enumerable=d.enumerable||!1;d.configurable=!0;if("value"in d)d.writable=!0;Object.defineProperty(a,d.key,d)}}function m(a,b,c){if(b)l(a.prototype,b);if(c)l(a,c);return a}function n(a,b,c){if("undefined"!=typeof Reflect&&Reflect.get){n=Reflect.get}else{n=function(a,b,c){var d=o(a,b);if(!d)return;var e=Object.getOwnPropertyDescriptor(d,b);if(e.get){return e.get.call(c)}return e.value}}return n(a,b,c||a)}function o(a,b){while(!Object.prototype.hasOwnProperty.call(a,b)){a=v(a);if(null===a)break}return a}function p(a,b){if("function"!=typeof b&&null!==b){throw new TypeError("Super expression must either be null or a function")}a.prototype=Object.create(b&&b.prototype,{constructor:{value:a,writable:!0,configurable:!0}});if(b)q(a,b)}function q(a,b){q=Object.setPrototypeOf||function(a,b){a.__proto__=b;return a};return q(a,b)}function r(a){return function(){var b=v(a),c;if(u()){var d=v(this).constructor;c=Reflect.construct(b,arguments,d)}else{c=b.apply(this,arguments)}return s(this,c)}}function s(a,b){if(b&&("object"===j(b)||"function"==typeof b)){return b}return t(a)}function t(a){if(void 0===a){throw new ReferenceError("this hasn't been initialised - super() hasn't been called")}return a}function u(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{Date.prototype.toString.call(Reflect.construct(Date,[],function(){}));return!0}catch(a){return!1}}function v(a){v=Object.setPrototypeOf?Object.getPrototypeOf:function(a){return a.__proto__||Object.getPrototypeOf(a)};return v(a)}var w=!1,x={PROCEED_BUTTON:"[data-action=\"proceed\"]",CANCEL_BUTTON:"[data-action=\"cancel\"]"},y=function(a){p(d,a);var e=r(d);function d(a){k(this,d);return e.call(this,a)}m(d,[{key:"registerEventListeners",value:function registerEventListeners(){var a=this;n(v(d.prototype),"registerEventListeners",this).call(this);this.getModal().on(c.default.events.activate,x.PROCEED_BUTTON,function(c,d){var e=b.default.Event(g.default.proceed);a.getRoot().trigger(e,a);if(!e.isDefaultPrevented()){a.hide();d.originalEvent.preventDefault()}});this.getModal().on(c.default.events.activate,x.CANCEL_BUTTON,function(c,d){var e=b.default.Event(f.default.cancel);a.getRoot().trigger(e,a);if(!e.isDefaultPrevented()){a.hide();d.originalEvent.preventDefault()}})}}]);return d}(d.default);a.default=y;y.TYPE="core_payment-modal_gateways";if(!w){h.default.register(y.TYPE,y,"core_payment/modal_gateways");w=!0}return a.default});
|
||||
//# sourceMappingURL=modal_gateways.min.js.map
|
1
payment/amd/build/modal_gateways.min.js.map
Normal file
1
payment/amd/build/modal_gateways.min.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sources":["../src/modal_gateways.js"],"names":["registered","SELECTORS","PROCEED_BUTTON","CANCEL_BUTTON","ModalGateways","root","getModal","on","CustomEvents","events","activate","e","data","proceedEvent","$","Event","PaymentEvents","proceed","getRoot","trigger","isDefaultPrevented","hide","originalEvent","preventDefault","cancelEvent","ModalEvents","cancel","Modal","TYPE","ModalRegistry","register"],"mappings":"gRAwBA,OACA,OACA,OACA,OACA,OACA,O,igEAEIA,CAAAA,CAAU,G,CACRC,CAAS,CAAG,CACdC,cAAc,CAAE,2BADF,CAEdC,aAAa,CAAE,0BAFD,C,CAKGC,C,+BAOjB,WAAYC,CAAZ,CAAkB,8BACRA,CADQ,CAEjB,C,0EAOwB,YAErB,2DAEA,KAAKC,QAAL,GAAgBC,EAAhB,CAAmBC,UAAaC,MAAb,CAAoBC,QAAvC,CAAiDT,CAAS,CAACC,cAA3D,CAA2E,SAACS,CAAD,CAAIC,CAAJ,CAAa,CACpF,GAAIC,CAAAA,CAAY,CAAGC,UAAEC,KAAF,CAAQC,UAAcC,OAAtB,CAAnB,CACA,CAAI,CAACC,OAAL,GAAeC,OAAf,CAAuBN,CAAvB,CAAqC,CAArC,EAEA,GAAI,CAACA,CAAY,CAACO,kBAAb,EAAL,CAAwC,CACpC,CAAI,CAACC,IAAL,GACAT,CAAI,CAACU,aAAL,CAAmBC,cAAnB,EACH,CACJ,CARD,EAUA,KAAKjB,QAAL,GAAgBC,EAAhB,CAAmBC,UAAaC,MAAb,CAAoBC,QAAvC,CAAiDT,CAAS,CAACE,aAA3D,CAA0E,SAACQ,CAAD,CAAIC,CAAJ,CAAa,CACnF,GAAIY,CAAAA,CAAW,CAAGV,UAAEC,KAAF,CAAQU,UAAYC,MAApB,CAAlB,CACA,CAAI,CAACR,OAAL,GAAeC,OAAf,CAAuBK,CAAvB,CAAoC,CAApC,EAEA,GAAI,CAACA,CAAW,CAACJ,kBAAZ,EAAL,CAAuC,CACnC,CAAI,CAACC,IAAL,GACAT,CAAI,CAACU,aAAL,CAAmBC,cAAnB,EACH,CACJ,CARD,CASH,C,cAvCsCI,S,cA0C3CvB,CAAa,CAACwB,IAAd,CAAqB,6BAArB,CAIA,GAAI,CAAC5B,CAAL,CAAiB,CACb6B,UAAcC,QAAd,CAAuB1B,CAAa,CAACwB,IAArC,CAA2CxB,CAA3C,CAA0D,6BAA1D,EACAJ,CAAU,GACb,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Contain the logic for the gateways modal: A modal with proceed and cancel buttons.\n *\n * @module core_payment/modal_gateways\n * @package core_payment\n * @copyright 2020 Shamim Rezaie <shamim@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\nimport CustomEvents from 'core/custom_interaction_events';\nimport Modal from 'core/modal';\nimport ModalEvents from 'core/modal_events';\nimport PaymentEvents from 'core_payment/events';\nimport ModalRegistry from 'core/modal_registry';\n\nlet registered = false;\nconst SELECTORS = {\n PROCEED_BUTTON: '[data-action=\"proceed\"]',\n CANCEL_BUTTON: '[data-action=\"cancel\"]',\n};\n\nexport default class ModalGateways extends Modal {\n\n /**\n * Constructor for the Modal.\n *\n * @param {object} root The root jQuery element for the modal\n */\n constructor(root) {\n super(root);\n }\n\n /**\n * Set up all of the event handling for the modal.\n *\n * @method registerEventListeners\n */\n registerEventListeners() {\n // Apply parent event listeners.\n super.registerEventListeners();\n\n this.getModal().on(CustomEvents.events.activate, SELECTORS.PROCEED_BUTTON, (e, data) => {\n var proceedEvent = $.Event(PaymentEvents.proceed);\n this.getRoot().trigger(proceedEvent, this);\n\n if (!proceedEvent.isDefaultPrevented()) {\n this.hide();\n data.originalEvent.preventDefault();\n }\n });\n\n this.getModal().on(CustomEvents.events.activate, SELECTORS.CANCEL_BUTTON, (e, data) => {\n var cancelEvent = $.Event(ModalEvents.cancel);\n this.getRoot().trigger(cancelEvent, this);\n\n if (!cancelEvent.isDefaultPrevented()) {\n this.hide();\n data.originalEvent.preventDefault();\n }\n });\n }\n}\n\nModalGateways.TYPE = 'core_payment-modal_gateways';\n\n// Automatically register with the modal registry the first time this module is imported so that you can create modals\n// of this type using the modal factory.\nif (!registered) {\n ModalRegistry.register(ModalGateways.TYPE, ModalGateways, 'core_payment/modal_gateways');\n registered = true;\n}\n"],"file":"modal_gateways.min.js"}
|
2
payment/amd/build/repository.min.js
vendored
Normal file
2
payment/amd/build/repository.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
define ("core_payment/repository",["exports","core/ajax"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.getAvailableGateways=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);var c=function(a,c,d){return b.default.call([{methodname:"core_payment_get_available_gateways",args:{component:a,paymentarea:c,itemid:d}}])[0]};a.getAvailableGateways=c});
|
||||
//# sourceMappingURL=repository.min.js.map
|
1
payment/amd/build/repository.min.js.map
Normal file
1
payment/amd/build/repository.min.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sources":["../src/repository.js"],"names":["getAvailableGateways","component","paymentArea","itemId","Ajax","call","methodname","args","paymentarea","itemid"],"mappings":"oKAwBA,uDAUO,GAAMA,CAAAA,CAAoB,CAAG,SAACC,CAAD,CAAYC,CAAZ,CAAyBC,CAAzB,CAAoC,CASpE,MAAOC,WAAKC,IAAL,CAAU,CARD,CACZC,UAAU,CAAE,qCADA,CAEZC,IAAI,CAAE,CACFN,SAAS,CAATA,CADE,CAEFO,WAAW,CAAEN,CAFX,CAGFO,MAAM,CAAEN,CAHN,CAFM,CAQC,CAAV,EAAqB,CAArB,CACV,CAVM,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Repository for payment subsystem.\n *\n * @module core_payment/repository\n * @package core_payment\n * @copyright 2020 Shamim Rezaie <shamim@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\n\n/**\n * Returns the list of gateways that can process payments in the given currency.\n *\n * @param {string} component\n * @param {string} paymentArea\n * @param {number} itemId\n * @returns {Promise<{shortname: string, name: string, description: String}[]>}\n */\nexport const getAvailableGateways = (component, paymentArea, itemId) => {\n const request = {\n methodname: 'core_payment_get_available_gateways',\n args: {\n component,\n paymentarea: paymentArea,\n itemid: itemId,\n }\n };\n return Ajax.call([request])[0];\n};\n"],"file":"repository.min.js"}
|
2
payment/amd/build/selectors.min.js
vendored
Normal file
2
payment/amd/build/selectors.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
define ("core_payment/selectors",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;a.default={elements:{gateways:"[data-region=\"gateways-container\"] input[type=\"radio\"]"},regions:{gatewaysContainer:"[data-region=\"gateways-container\"]",costContainer:"[data-region=\"fee-breakdown-container\"]"},values:{gateway:"[data-region=\"gateways-container\"] input[type=\"radio\"]:checked"}};return a.default});
|
||||
//# sourceMappingURL=selectors.min.js.map
|
1
payment/amd/build/selectors.min.js.map
Normal file
1
payment/amd/build/selectors.min.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sources":["../src/selectors.js"],"names":["elements","gateways","regions","gatewaysContainer","costContainer","values","gateway"],"mappings":"kJAwBe,CACXA,QAAQ,CAAE,CACNC,QAAQ,CAAE,4DADJ,CADC,CAIXC,OAAO,CAAE,CACLC,iBAAiB,CAAE,sCADd,CAELC,aAAa,CAAE,2CAFV,CAJE,CAQXC,MAAM,CAAE,CACJC,OAAO,CAAE,oEADL,CARG,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Define all of the selectors we will be using on the payment interface.\n *\n * @module core_payment/selectors\n * @package core_payment\n * @copyright 2019 Shamim Rezaie <shamim@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport default {\n elements: {\n gateways: '[data-region=\"gateways-container\"] input[type=\"radio\"]',\n },\n regions: {\n gatewaysContainer: '[data-region=\"gateways-container\"]',\n costContainer: '[data-region=\"fee-breakdown-container\"]',\n },\n values: {\n gateway: '[data-region=\"gateways-container\"] input[type=\"radio\"]:checked',\n },\n};\n"],"file":"selectors.min.js"}
|
27
payment/amd/src/events.js
Normal file
27
payment/amd/src/events.js
Normal file
@ -0,0 +1,27 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Contain the events the payment modal can fire.
|
||||
*
|
||||
* @module core_payment/events
|
||||
* @package core_payment
|
||||
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
export default {
|
||||
proceed: 'core_payment-modal_gateways:proceed',
|
||||
};
|
193
payment/amd/src/gateways_modal.js
Normal file
193
payment/amd/src/gateways_modal.js
Normal file
@ -0,0 +1,193 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Contain the logic for the gateways modal.
|
||||
*
|
||||
* @module core_payment/gateways_modal
|
||||
* @package core_payment
|
||||
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import ModalFactory from 'core/modal_factory';
|
||||
import Templates from 'core/templates';
|
||||
import {get_string as getString} from 'core/str';
|
||||
import {getAvailableGateways} from './repository';
|
||||
import Selectors from './selectors';
|
||||
import ModalEvents from 'core/modal_events';
|
||||
import PaymentEvents from 'core_payment/events';
|
||||
import {add as addToast, addToastRegion} from 'core/toast';
|
||||
import Notification from 'core/notification';
|
||||
import ModalGateways from './modal_gateways';
|
||||
|
||||
/**
|
||||
* Register event listeners for the module.
|
||||
*/
|
||||
const registerEventListeners = () => {
|
||||
document.addEventListener('click', e => {
|
||||
const gatewayTrigger = e.target.closest('[data-action="core_payment/triggerPayment"]');
|
||||
if (gatewayTrigger) {
|
||||
e.preventDefault();
|
||||
|
||||
show(gatewayTrigger, {focusOnClose: e.target});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Shows the gateway selector modal.
|
||||
*
|
||||
* @param {HTMLElement} rootNode
|
||||
* @param {Object} options - Additional options
|
||||
* @param {HTMLElement} options.focusOnClose The element to focus on when the modal is closed.
|
||||
*/
|
||||
const show = async(rootNode, {
|
||||
focusOnClose = null,
|
||||
} = {}) => {
|
||||
const modal = await ModalFactory.create({
|
||||
type: ModalGateways.TYPE,
|
||||
title: await getString('selectpaymenttype', 'core_payment'),
|
||||
body: await Templates.render('core_payment/gateways_modal', {}),
|
||||
});
|
||||
|
||||
const rootElement = modal.getRoot()[0];
|
||||
addToastRegion(rootElement);
|
||||
|
||||
modal.show();
|
||||
|
||||
modal.getRoot().on(ModalEvents.hidden, () => {
|
||||
// Destroy when hidden.
|
||||
modal.destroy();
|
||||
try {
|
||||
focusOnClose.focus();
|
||||
} catch (e) {
|
||||
// eslint-disable-line
|
||||
}
|
||||
});
|
||||
|
||||
modal.getRoot().on(PaymentEvents.proceed, (e) => {
|
||||
const gateway = (rootElement.querySelector(Selectors.values.gateway) || {value: ''}).value;
|
||||
|
||||
if (gateway) {
|
||||
processPayment(
|
||||
gateway,
|
||||
rootNode.dataset.component,
|
||||
rootNode.dataset.paymentarea,
|
||||
rootNode.dataset.itemid,
|
||||
rootNode.dataset.description
|
||||
)
|
||||
.then(message => {
|
||||
modal.hide();
|
||||
Notification.addNotification({
|
||||
message: message,
|
||||
type: 'success',
|
||||
});
|
||||
location.reload();
|
||||
|
||||
// The following return statement is never reached. It is put here just to make eslint happy.
|
||||
return message;
|
||||
})
|
||||
.catch(message => Notification.alert('', message));
|
||||
} else {
|
||||
// We cannot use await in the following line.
|
||||
// The reason is that we are preventing the default action of the save event being triggered,
|
||||
// therefore we cannot define the event handler function asynchronous.
|
||||
getString('nogatewayselected', 'core_payment').then(message => addToast(message)).catch();
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
// Re-calculate the cost when gateway is changed.
|
||||
rootElement.addEventListener('change', e => {
|
||||
if (e.target.matches(Selectors.elements.gateways)) {
|
||||
updateCostRegion(rootElement, rootNode.dataset.cost);
|
||||
}
|
||||
});
|
||||
|
||||
const gateways = await getAvailableGateways(rootNode.dataset.component, rootNode.dataset.paymentarea, rootNode.dataset.itemid);
|
||||
const context = {
|
||||
gateways
|
||||
};
|
||||
|
||||
const {html, js} = await Templates.renderForPromise('core_payment/gateways', context);
|
||||
Templates.replaceNodeContents(rootElement.querySelector(Selectors.regions.gatewaysContainer), html, js);
|
||||
selectSingleGateway(rootElement);
|
||||
await updateCostRegion(rootElement, rootNode.dataset.cost);
|
||||
};
|
||||
|
||||
/**
|
||||
* Auto-select the gateway if there is only one gateway.
|
||||
*
|
||||
* @param {HTMLElement} root An HTMLElement that contains the cost region
|
||||
*/
|
||||
const selectSingleGateway = root => {
|
||||
const gateways = root.querySelectorAll(Selectors.elements.gateways);
|
||||
|
||||
if (gateways.length == 1) {
|
||||
gateways[0].checked = true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Shows the cost of the item the user is purchasing in the cost region.
|
||||
*
|
||||
* @param {HTMLElement} root An HTMLElement that contains the cost region
|
||||
* @param {string} defaultCost The default cost that is going to be displayed if no gateway is selected
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const updateCostRegion = async(root, defaultCost = '') => {
|
||||
const gatewayElement = root.querySelector(Selectors.values.gateway);
|
||||
const surcharge = parseInt((gatewayElement || {dataset: {surcharge: 0}}).dataset.surcharge);
|
||||
const cost = (gatewayElement || {dataset: {cost: defaultCost}}).dataset.cost;
|
||||
|
||||
const {html, js} = await Templates.renderForPromise('core_payment/fee_breakdown', {fee: cost, surcharge});
|
||||
Templates.replaceNodeContents(root.querySelector(Selectors.regions.costContainer), html, js);
|
||||
};
|
||||
|
||||
/**
|
||||
* Process payment using the selected gateway.
|
||||
*
|
||||
* @param {string} gateway The gateway to be used for payment
|
||||
* @param {string} component Name of the component that the itemId belongs to
|
||||
* @param {string} paymentArea Name of the area in the component that the itemId belongs to
|
||||
* @param {number} itemId An internal identifier that is used by the component
|
||||
* @param {string} description Description of the payment
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
const processPayment = async(gateway, component, paymentArea, itemId, description) => {
|
||||
const paymentMethod = await import(`paygw_${gateway}/gateways_modal`);
|
||||
return paymentMethod.process(component, paymentArea, itemId, description);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set up the payment actions.
|
||||
*/
|
||||
export const init = () => {
|
||||
if (!init.initialised) {
|
||||
// Event listeners should only be registered once.
|
||||
init.initialised = true;
|
||||
registerEventListeners();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether the init function was called before.
|
||||
*
|
||||
* @static
|
||||
* @type {boolean}
|
||||
*/
|
||||
init.initialised = false;
|
87
payment/amd/src/modal_gateways.js
Normal file
87
payment/amd/src/modal_gateways.js
Normal file
@ -0,0 +1,87 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Contain the logic for the gateways modal: A modal with proceed and cancel buttons.
|
||||
*
|
||||
* @module core_payment/modal_gateways
|
||||
* @package core_payment
|
||||
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import $ from 'jquery';
|
||||
import CustomEvents from 'core/custom_interaction_events';
|
||||
import Modal from 'core/modal';
|
||||
import ModalEvents from 'core/modal_events';
|
||||
import PaymentEvents from 'core_payment/events';
|
||||
import ModalRegistry from 'core/modal_registry';
|
||||
|
||||
let registered = false;
|
||||
const SELECTORS = {
|
||||
PROCEED_BUTTON: '[data-action="proceed"]',
|
||||
CANCEL_BUTTON: '[data-action="cancel"]',
|
||||
};
|
||||
|
||||
export default class ModalGateways extends Modal {
|
||||
|
||||
/**
|
||||
* Constructor for the Modal.
|
||||
*
|
||||
* @param {object} root The root jQuery element for the modal
|
||||
*/
|
||||
constructor(root) {
|
||||
super(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up all of the event handling for the modal.
|
||||
*
|
||||
* @method registerEventListeners
|
||||
*/
|
||||
registerEventListeners() {
|
||||
// Apply parent event listeners.
|
||||
super.registerEventListeners();
|
||||
|
||||
this.getModal().on(CustomEvents.events.activate, SELECTORS.PROCEED_BUTTON, (e, data) => {
|
||||
var proceedEvent = $.Event(PaymentEvents.proceed);
|
||||
this.getRoot().trigger(proceedEvent, this);
|
||||
|
||||
if (!proceedEvent.isDefaultPrevented()) {
|
||||
this.hide();
|
||||
data.originalEvent.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
this.getModal().on(CustomEvents.events.activate, SELECTORS.CANCEL_BUTTON, (e, data) => {
|
||||
var cancelEvent = $.Event(ModalEvents.cancel);
|
||||
this.getRoot().trigger(cancelEvent, this);
|
||||
|
||||
if (!cancelEvent.isDefaultPrevented()) {
|
||||
this.hide();
|
||||
data.originalEvent.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ModalGateways.TYPE = 'core_payment-modal_gateways';
|
||||
|
||||
// Automatically register with the modal registry the first time this module is imported so that you can create modals
|
||||
// of this type using the modal factory.
|
||||
if (!registered) {
|
||||
ModalRegistry.register(ModalGateways.TYPE, ModalGateways, 'core_payment/modal_gateways');
|
||||
registered = true;
|
||||
}
|
45
payment/amd/src/repository.js
Normal file
45
payment/amd/src/repository.js
Normal file
@ -0,0 +1,45 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Repository for payment subsystem.
|
||||
*
|
||||
* @module core_payment/repository
|
||||
* @package core_payment
|
||||
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import Ajax from 'core/ajax';
|
||||
|
||||
/**
|
||||
* Returns the list of gateways that can process payments in the given currency.
|
||||
*
|
||||
* @param {string} component
|
||||
* @param {string} paymentArea
|
||||
* @param {number} itemId
|
||||
* @returns {Promise<{shortname: string, name: string, description: String}[]>}
|
||||
*/
|
||||
export const getAvailableGateways = (component, paymentArea, itemId) => {
|
||||
const request = {
|
||||
methodname: 'core_payment_get_available_gateways',
|
||||
args: {
|
||||
component,
|
||||
paymentarea: paymentArea,
|
||||
itemid: itemId,
|
||||
}
|
||||
};
|
||||
return Ajax.call([request])[0];
|
||||
};
|
36
payment/amd/src/selectors.js
Normal file
36
payment/amd/src/selectors.js
Normal file
@ -0,0 +1,36 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Define all of the selectors we will be using on the payment interface.
|
||||
*
|
||||
* @module core_payment/selectors
|
||||
* @package core_payment
|
||||
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
export default {
|
||||
elements: {
|
||||
gateways: '[data-region="gateways-container"] input[type="radio"]',
|
||||
},
|
||||
regions: {
|
||||
gatewaysContainer: '[data-region="gateways-container"]',
|
||||
costContainer: '[data-region="fee-breakdown-container"]',
|
||||
},
|
||||
values: {
|
||||
gateway: '[data-region="gateways-container"] input[type="radio"]:checked',
|
||||
},
|
||||
};
|
156
payment/classes/account.php
Normal file
156
payment/classes/account.php
Normal 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
payment/classes/account_gateway.php
Normal file
106
payment/classes/account_gateway.php
Normal 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
payment/classes/event/account_created.php
Normal file
94
payment/classes/event/account_created.php
Normal 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
payment/classes/event/account_deleted.php
Normal file
94
payment/classes/event/account_deleted.php
Normal 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
payment/classes/event/account_updated.php
Normal file
101
payment/classes/event/account_updated.php
Normal 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');
|
||||
}
|
||||
}
|
106
payment/classes/external/get_available_gateways.php
vendored
Normal file
106
payment/classes/external/get_available_gateways.php
vendored
Normal 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/>.
|
||||
|
||||
/**
|
||||
* 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 external_api;
|
||||
use external_function_parameters;
|
||||
use external_value;
|
||||
use external_single_structure;
|
||||
use external_multiple_structure;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/externallib.php');
|
||||
|
||||
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_TEXT, '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
payment/classes/form/account.php
Normal file
66
payment/classes/form/account.php
Normal 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
payment/classes/form/account_gateway.php
Normal file
147
payment/classes/form/account_gateway.php
Normal 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
payment/classes/gateway.php
Normal file
66
payment/classes/gateway.php
Normal 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
|
||||
*/
|
||||
public abstract 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
|
||||
*/
|
||||
public abstract 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');
|
||||
}
|
||||
}
|
||||
}
|
399
payment/classes/helper.php
Normal file
399
payment/classes/helper.php
Normal file
@ -0,0 +1,399 @@
|
||||
<?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 += 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
|
||||
* @param string $paymentarea
|
||||
* @param int $itemid
|
||||
* @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 itemid belongs to
|
||||
* @param string $paymentarea
|
||||
* @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);
|
||||
|
||||
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,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $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 itemid belongs to
|
||||
* @param string $paymentarea
|
||||
* @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]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the gateway configuration for given component and gateway
|
||||
*
|
||||
* @param string $component
|
||||
* @param string $paymentarea
|
||||
* @param int $itemid
|
||||
* @param string $gatewayname
|
||||
* @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 itemid belongs to
|
||||
* @param string $paymentarea
|
||||
* @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 itemid belongs to
|
||||
* @param string $paymentarea
|
||||
* @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);
|
||||
}
|
||||
}
|
53
payment/classes/local/callback/service_provider.php
Normal file
53
payment/classes/local/callback/service_provider.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?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 {
|
||||
|
||||
/**
|
||||
* @param string $paymentarea
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* @param string $paymentarea
|
||||
* @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;
|
||||
}
|
70
payment/classes/local/entities/payable.php
Normal file
70
payment/classes/local/entities/payable.php
Normal file
@ -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;
|
||||
}
|
||||
}
|
69
payment/classes/privacy/consumer_provider.php
Normal file
69
payment/classes/privacy/consumer_provider.php
Normal file
@ -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);
|
||||
}
|
37
payment/classes/privacy/paygw_provider.php
Normal file
37
payment/classes/privacy/paygw_provider.php
Normal file
@ -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
payment/classes/privacy/provider.php
Normal file
338
payment/classes/privacy/provider.php
Normal 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);
|
||||
}
|
||||
}
|
2
payment/gateway/paypal/amd/build/gateways_modal.min.js
vendored
Normal file
2
payment/gateway/paypal/amd/build/gateways_modal.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("paygw_paypal/gateways_modal",["exports","./repository","core/templates","core/truncate","core/modal_factory","core/modal_events","core/str"],function(a,b,c,d,e,f,g){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.process=void 0;b=j(b);c=h(c);d=h(d);e=h(e);f=h(f);function h(a){return a&&a.__esModule?a:{default:a}}function i(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;i=function(){return a};return a}function j(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=i();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function k(a,b){return r(a)||q(a,b)||m(a,b)||l()}function l(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function m(a,b){if(!a)return;if("string"==typeof a)return p(a,b);var c=Object.prototype.toString.call(a).slice(8,-1);if("Object"===c&&a.constructor)c=a.constructor.name;if("Map"===c||"Set"===c)return Array.from(c);if("Arguments"===c||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c))return p(a,b)}function p(a,b){if(null==b||b>a.length)b=a.length;for(var c=0,d=Array(b);c<b;c++){d[c]=a[c]}return d}function q(a,b){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(a)))return;var c=[],d=!0,e=!1,f=void 0;try{for(var g=a[Symbol.iterator](),h;!(d=(h=g.next()).done);d=!0){c.push(h.value);if(b&&c.length===b)break}}catch(a){e=!0;f=a}finally{try{if(!d&&null!=g["return"])g["return"]()}finally{if(e)throw f}}return c}function r(a){if(Array.isArray(a))return a}function s(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function t(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){s(h,d,e,f,g,"next",a)}function g(a){s(h,d,e,f,g,"throw",a)}f(void 0)})}}var u=function(){var a=t(regeneratorRuntime.mark(function a(){var b;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:a.t0=e.default;a.next=3;return c.default.render("paygw_paypal/paypal_button_placeholder",{});case 3:a.t1=a.sent;a.t2={body:a.t1};a.next=7;return a.t0.create.call(a.t0,a.t2);case 7:b=a.sent;b.show();return a.abrupt("return",b);case 10:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}(),v=function(a,c,e,h){return Promise.all([u(),b.getConfigForJs(a,c,e)]).then(function(a){var b=k(a,2),c=b[0],d=b[1];c.getRoot().on(f.default.hidden,function(){c.destroy()});return Promise.all([c,d,w(d.clientid,d.currency)])}).then(function(i){var j=k(i,2),l=j[0],m=j[1];l.setBody("");return new Promise(function(i){window.paypal.Buttons({createOrder:function createOrder(a,b){return b.order.create({purchase_units:[{amount:{currency_code:m.currency_code,value:m.cost},description:d.default.truncate(h,{length:127,stripTags:!0})}],application_context:{shipping_preference:"NO_SHIPPING",brand_name:d.default.truncate(m.brandname,{length:127,stripTags:!0})}})},onApprove:function onApprove(d){l.getRoot().on(f.default.outsideClick,function(a){a.preventDefault()});l.setBody((0,g.get_string)("authorising","paygw_paypal"));b.markTransactionComplete(a,c,e,d.orderID).then(function(a){l.hide();return a}).then(i)}}).render(l.getBody()[0])})}).then(function(a){if(a.success){return Promise.resolve(a.message)}return Promise.reject(a.message)})};a.process=v;var w=function(a,b){var c="https://www.paypal.com/sdk/js?client-id=".concat(a,"¤cy=").concat(b);if(w.currentlyloaded===c){return Promise.resolve()}if(w.currentlyloaded){var e=document.querySelector("script[src=\"".concat(w.currentlyloaded,"\"]"));if(e){e.parentNode.removeChild(e)}}var d=document.createElement("script");return new Promise(function(a){if(d.readyState){d.onreadystatechange=function(){if("complete"==this.readyState||"loaded"==this.readyState){this.onreadystatechange=null;a()}}}else{d.onload=function(){a()}}d.setAttribute("src",c);document.head.appendChild(d);w.currentlyloaded=c})};w.currentlyloaded=""});
|
||||
//# sourceMappingURL=gateways_modal.min.js.map
|
File diff suppressed because one or more lines are too long
2
payment/gateway/paypal/amd/build/repository.min.js
vendored
Normal file
2
payment/gateway/paypal/amd/build/repository.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
define ("paygw_paypal/repository",["exports","core/ajax"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.markTransactionComplete=a.getConfigForJs=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);var c=function(a,c,d){return b.default.call([{methodname:"paygw_paypal_get_config_for_js",args:{component:a,paymentarea:c,itemid:d}}])[0]};a.getConfigForJs=c;var d=function(a,c,d,e){return b.default.call([{methodname:"paygw_paypal_create_transaction_complete",args:{component:a,paymentarea:c,itemid:d,orderid:e}}])[0]};a.markTransactionComplete=d});
|
||||
//# sourceMappingURL=repository.min.js.map
|
1
payment/gateway/paypal/amd/build/repository.min.js.map
Normal file
1
payment/gateway/paypal/amd/build/repository.min.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sources":["../src/repository.js"],"names":["getConfigForJs","component","paymentArea","itemId","Ajax","call","methodname","args","paymentarea","itemid","markTransactionComplete","orderId","orderid"],"mappings":"wLAwBA,uDAUO,GAAMA,CAAAA,CAAc,CAAG,SAACC,CAAD,CAAYC,CAAZ,CAAyBC,CAAzB,CAAoC,CAU9D,MAAOC,WAAKC,IAAL,CAAU,CATD,CACZC,UAAU,CAAE,gCADA,CAEZC,IAAI,CAAE,CACFN,SAAS,CAATA,CADE,CAEFO,WAAW,CAAEN,CAFX,CAGFO,MAAM,CAAEN,CAHN,CAFM,CASC,CAAV,EAAqB,CAArB,CACV,CAXM,C,mBAsBA,GAAMO,CAAAA,CAAuB,CAAG,SAACT,CAAD,CAAYC,CAAZ,CAAyBC,CAAzB,CAAiCQ,CAAjC,CAA6C,CAWhF,MAAOP,WAAKC,IAAL,CAAU,CAVD,CACZC,UAAU,CAAE,0CADA,CAEZC,IAAI,CAAE,CACFN,SAAS,CAATA,CADE,CAEFO,WAAW,CAAEN,CAFX,CAGFO,MAAM,CAAEN,CAHN,CAIFS,OAAO,CAAED,CAJP,CAFM,CAUC,CAAV,EAAqB,CAArB,CACV,CAZM,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * PayPal repository module to encapsulate all of the AJAX requests that can be sent for PayPal.\n *\n * @module paygw_paypal/repository\n * @package paygw_paypal\n * @copyright 2020 Shamim Rezaie <shamim@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\n\n/**\n * Return the PayPal JavaScript SDK URL.\n *\n * @param {string} component Name of the component that the itemId belongs to\n * @param {string} paymentArea The area of the component that the itemId belongs to\n * @param {number} itemId An internal identifier that is used by the component\n * @returns {Promise<{clientid: string, brandname: string, cost: number, currency: string}>}\n */\nexport const getConfigForJs = (component, paymentArea, itemId) => {\n const request = {\n methodname: 'paygw_paypal_get_config_for_js',\n args: {\n component,\n paymentarea: paymentArea,\n itemid: itemId,\n },\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Call server to validate and capture payment for order.\n *\n * @param {string} component Name of the component that the itemId belongs to\n * @param {string} paymentArea The area of the component that the itemId belongs to\n * @param {number} itemId An internal identifier that is used by the component\n * @param {string} orderId The order id coming back from PayPal\n * @returns {*}\n */\nexport const markTransactionComplete = (component, paymentArea, itemId, orderId) => {\n const request = {\n methodname: 'paygw_paypal_create_transaction_complete',\n args: {\n component,\n paymentarea: paymentArea,\n itemid: itemId,\n orderid: orderId,\n },\n };\n\n return Ajax.call([request])[0];\n};\n"],"file":"repository.min.js"}
|
174
payment/gateway/paypal/amd/src/gateways_modal.js
Normal file
174
payment/gateway/paypal/amd/src/gateways_modal.js
Normal file
@ -0,0 +1,174 @@
|
||||
// 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 module is responsible for PayPal content in the gateways modal.
|
||||
*
|
||||
* @module paygw_paypal/gateway_modal
|
||||
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import * as Repository from './repository';
|
||||
import Templates from 'core/templates';
|
||||
import Truncate from 'core/truncate';
|
||||
import ModalFactory from 'core/modal_factory';
|
||||
import ModalEvents from 'core/modal_events';
|
||||
import {get_string as getString} from 'core/str';
|
||||
|
||||
/**
|
||||
* Creates and shows a modal that contains a placeholder.
|
||||
*
|
||||
* @returns {Promise<Modal>}
|
||||
*/
|
||||
const showModalWithPlaceholder = async() => {
|
||||
const modal = await ModalFactory.create({
|
||||
body: await Templates.render('paygw_paypal/paypal_button_placeholder', {})
|
||||
});
|
||||
modal.show();
|
||||
return modal;
|
||||
};
|
||||
|
||||
/**
|
||||
* Process the payment.
|
||||
*
|
||||
* @param {string} component Name of the component that the itemId belongs to
|
||||
* @param {string} paymentArea The area of the component that the itemId belongs to
|
||||
* @param {number} itemId An internal identifier that is used by the component
|
||||
* @param {string} description Description of the payment
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
export const process = (component, paymentArea, itemId, description) => {
|
||||
return Promise.all([
|
||||
showModalWithPlaceholder(),
|
||||
Repository.getConfigForJs(component, paymentArea, itemId),
|
||||
])
|
||||
.then(([modal, paypalConfig]) => {
|
||||
modal.getRoot().on(ModalEvents.hidden, () => {
|
||||
// Destroy when hidden.
|
||||
modal.destroy();
|
||||
});
|
||||
|
||||
return Promise.all([
|
||||
modal,
|
||||
paypalConfig,
|
||||
switchSdk(paypalConfig.clientid, paypalConfig.currency),
|
||||
]);
|
||||
})
|
||||
.then(([modal, paypalConfig]) => {
|
||||
// We have to clear the body. The render method in paypal.Buttons will render everything.
|
||||
modal.setBody('');
|
||||
|
||||
return new Promise(resolve => {
|
||||
window.paypal.Buttons({
|
||||
// Set up the transaction.
|
||||
createOrder: function(data, actions) {
|
||||
return actions.order.create({
|
||||
purchase_units: [{ // eslint-disable-line
|
||||
amount: {
|
||||
currency_code: paypalConfig.currency_code, // eslint-disable-line
|
||||
value: paypalConfig.cost,
|
||||
},
|
||||
description: Truncate.truncate(description, {length: 127, stripTags: true}),
|
||||
}],
|
||||
application_context: { // eslint-disable-line
|
||||
shipping_preference: 'NO_SHIPPING', // eslint-disable-line
|
||||
brand_name: Truncate.truncate(paypalConfig.brandname, {length: 127, stripTags: true}), // eslint-disable-line
|
||||
},
|
||||
});
|
||||
},
|
||||
// Finalise the transaction.
|
||||
onApprove: function(data) {
|
||||
modal.getRoot().on(ModalEvents.outsideClick, (e) => {
|
||||
// Prevent closing the modal when clicking outside of it.
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
modal.setBody(getString('authorising', 'paygw_paypal'));
|
||||
|
||||
Repository.markTransactionComplete(component, paymentArea, itemId, data.orderID)
|
||||
.then(res => {
|
||||
modal.hide();
|
||||
return res;
|
||||
})
|
||||
.then(resolve);
|
||||
}
|
||||
}).render(modal.getBody()[0]);
|
||||
});
|
||||
})
|
||||
.then(res => {
|
||||
if (res.success) {
|
||||
return Promise.resolve(res.message);
|
||||
}
|
||||
|
||||
return Promise.reject(res.message);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Unloads the previously loaded PayPal JavaScript SDK, and loads a new one.
|
||||
*
|
||||
* @param {string} clientId PayPal client ID
|
||||
* @param {string} currency The currency
|
||||
* @returns {Promise}
|
||||
*/
|
||||
const switchSdk = (clientId, currency) => {
|
||||
const sdkUrl = `https://www.paypal.com/sdk/js?client-id=${clientId}¤cy=${currency}`;
|
||||
|
||||
// Check to see if this file has already been loaded. If so just go straight to the func.
|
||||
if (switchSdk.currentlyloaded === sdkUrl) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// PayPal can only work with one currency at the same time. We have to unload the previously loaded script
|
||||
// if it was loaded for a different currency. Weird way indeed, but the only way.
|
||||
// See: https://github.com/paypal/paypal-checkout-components/issues/1180
|
||||
if (switchSdk.currentlyloaded) {
|
||||
const suspectedScript = document.querySelector(`script[src="${switchSdk.currentlyloaded}"]`);
|
||||
if (suspectedScript) {
|
||||
suspectedScript.parentNode.removeChild(suspectedScript);
|
||||
}
|
||||
}
|
||||
|
||||
const script = document.createElement('script');
|
||||
|
||||
return new Promise(resolve => {
|
||||
if (script.readyState) {
|
||||
script.onreadystatechange = function() {
|
||||
if (this.readyState == 'complete' || this.readyState == 'loaded') {
|
||||
this.onreadystatechange = null;
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
script.onload = function() {
|
||||
resolve();
|
||||
};
|
||||
}
|
||||
|
||||
script.setAttribute('src', sdkUrl);
|
||||
document.head.appendChild(script);
|
||||
|
||||
switchSdk.currentlyloaded = sdkUrl;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Holds the full url of loaded PayPal JavaScript SDK.
|
||||
*
|
||||
* @static
|
||||
* @type {string}
|
||||
*/
|
||||
switchSdk.currentlyloaded = '';
|
69
payment/gateway/paypal/amd/src/repository.js
Normal file
69
payment/gateway/paypal/amd/src/repository.js
Normal file
@ -0,0 +1,69 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* PayPal repository module to encapsulate all of the AJAX requests that can be sent for PayPal.
|
||||
*
|
||||
* @module paygw_paypal/repository
|
||||
* @package paygw_paypal
|
||||
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import Ajax from 'core/ajax';
|
||||
|
||||
/**
|
||||
* Return the PayPal JavaScript SDK URL.
|
||||
*
|
||||
* @param {string} component Name of the component that the itemId belongs to
|
||||
* @param {string} paymentArea The area of the component that the itemId belongs to
|
||||
* @param {number} itemId An internal identifier that is used by the component
|
||||
* @returns {Promise<{clientid: string, brandname: string, cost: number, currency: string}>}
|
||||
*/
|
||||
export const getConfigForJs = (component, paymentArea, itemId) => {
|
||||
const request = {
|
||||
methodname: 'paygw_paypal_get_config_for_js',
|
||||
args: {
|
||||
component,
|
||||
paymentarea: paymentArea,
|
||||
itemid: itemId,
|
||||
},
|
||||
};
|
||||
|
||||
return Ajax.call([request])[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* Call server to validate and capture payment for order.
|
||||
*
|
||||
* @param {string} component Name of the component that the itemId belongs to
|
||||
* @param {string} paymentArea The area of the component that the itemId belongs to
|
||||
* @param {number} itemId An internal identifier that is used by the component
|
||||
* @param {string} orderId The order id coming back from PayPal
|
||||
* @returns {*}
|
||||
*/
|
||||
export const markTransactionComplete = (component, paymentArea, itemId, orderId) => {
|
||||
const request = {
|
||||
methodname: 'paygw_paypal_create_transaction_complete',
|
||||
args: {
|
||||
component,
|
||||
paymentarea: paymentArea,
|
||||
itemid: itemId,
|
||||
orderid: orderId,
|
||||
},
|
||||
};
|
||||
|
||||
return Ajax.call([request])[0];
|
||||
};
|
94
payment/gateway/paypal/classes/external/get_config_for_js.php
vendored
Normal file
94
payment/gateway/paypal/classes/external/get_config_for_js.php
vendored
Normal 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/>.
|
||||
|
||||
/**
|
||||
* This class contains a list of webservice functions related to the PayPal payment gateway.
|
||||
*
|
||||
* @package paygw_paypal
|
||||
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace paygw_paypal\external;
|
||||
|
||||
use core_payment\helper;
|
||||
use external_api;
|
||||
use external_function_parameters;
|
||||
use external_value;
|
||||
use external_single_structure;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/externallib.php');
|
||||
|
||||
class get_config_for_js 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 config values required by the PayPal JavaScript SDK.
|
||||
*
|
||||
* @param string $component
|
||||
* @param string $paymentarea
|
||||
* @param int $itemid
|
||||
* @return string[]
|
||||
*/
|
||||
public static function execute(string $component, string $paymentarea, int $itemid): array {
|
||||
self::validate_parameters(self::execute_parameters(), [
|
||||
'component' => $component,
|
||||
'paymentarea' => $paymentarea,
|
||||
'itemid' => $itemid,
|
||||
]);
|
||||
|
||||
$config = helper::get_gateway_configuration($component, $paymentarea, $itemid, 'paypal');
|
||||
$payable = helper::get_payable($component, $paymentarea, $itemid);
|
||||
$surcharge = helper::get_gateway_surcharge('paypal');
|
||||
|
||||
return [
|
||||
'clientid' => $config['clientid'],
|
||||
'brandname' => $config['brandname'],
|
||||
'cost' => helper::get_rounded_cost($payable->get_amount(), $payable->get_currency(), $surcharge),
|
||||
'currency' => $payable->get_currency(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of method result value.
|
||||
*
|
||||
* @return external_single_structure
|
||||
*/
|
||||
public static function execute_returns(): external_single_structure {
|
||||
return new external_single_structure([
|
||||
'clientid' => new external_value(PARAM_TEXT, 'PayPal client ID'),
|
||||
'brandname' => new external_value(PARAM_TEXT, 'Brand name'),
|
||||
'cost' => new external_value(PARAM_FLOAT, 'Cost with gateway surcharge'),
|
||||
'currency' => new external_value(PARAM_TEXT, 'Currency'),
|
||||
]);
|
||||
}
|
||||
}
|
153
payment/gateway/paypal/classes/external/transaction_complete.php
vendored
Normal file
153
payment/gateway/paypal/classes/external/transaction_complete.php
vendored
Normal file
@ -0,0 +1,153 @@
|
||||
<?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 class contains a list of webservice functions related to the PayPal payment gateway.
|
||||
*
|
||||
* @package paygw_paypal
|
||||
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace paygw_paypal\external;
|
||||
|
||||
use core_payment\helper;
|
||||
use external_api;
|
||||
use external_function_parameters;
|
||||
use external_value;
|
||||
use core_payment\helper as payment_helper;
|
||||
use paygw_paypal\paypal_helper;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/externallib.php');
|
||||
|
||||
class transaction_complete extends external_api {
|
||||
|
||||
/**
|
||||
* Returns description of method parameters.
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function execute_parameters() {
|
||||
return new external_function_parameters([
|
||||
'component' => new external_value(PARAM_COMPONENT, 'The component name'),
|
||||
'paymentarea' => new external_value(PARAM_AREA, 'Payment area in the component'),
|
||||
'itemid' => new external_value(PARAM_INT, 'The item id in the context of the component area'),
|
||||
'orderid' => new external_value(PARAM_TEXT, 'The order id coming back from PayPal'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform what needs to be done when a transaction is reported to be complete.
|
||||
* This function does not take cost as a parameter as we cannot rely on any provided value.
|
||||
*
|
||||
* @param string $component Name of the component that the itemid belongs to
|
||||
* @param string $paymentarea
|
||||
* @param int $itemid An internal identifier that is used by the component
|
||||
* @param string $orderid PayPal order ID
|
||||
* @return array
|
||||
*/
|
||||
public static function execute(string $component, string $paymentarea, int $itemid, string $orderid): array {
|
||||
global $USER, $DB;
|
||||
|
||||
self::validate_parameters(self::execute_parameters(), [
|
||||
'component' => $component,
|
||||
'paymentarea' => $paymentarea,
|
||||
'itemid' => $itemid,
|
||||
'orderid' => $orderid,
|
||||
]);
|
||||
|
||||
$config = (object)helper::get_gateway_configuration($component, $paymentarea, $itemid, 'paypal');
|
||||
$sandbox = $config->environment == 'sandbox';
|
||||
|
||||
$payable = payment_helper::get_payable($component, $paymentarea, $itemid);
|
||||
$currency = $payable->get_currency();
|
||||
|
||||
// Add surcharge if there is any.
|
||||
$surcharge = helper::get_gateway_surcharge('paypal');
|
||||
$amount = helper::get_rounded_cost($payable->get_amount(), $currency, $surcharge);
|
||||
|
||||
$paypalhelper = new paypal_helper($config->clientid, $config->secret, $sandbox);
|
||||
$orderdetails = $paypalhelper->get_order_details($orderid);
|
||||
|
||||
$success = false;
|
||||
$message = '';
|
||||
|
||||
if ($orderdetails) {
|
||||
if ($orderdetails['status'] == paypal_helper::ORDER_STATUS_APPROVED &&
|
||||
$orderdetails['intent'] == paypal_helper::ORDER_INTENT_CAPTURE) {
|
||||
$item = $orderdetails['purchase_units'][0];
|
||||
if ($item['amount']['value'] == $amount && $item['amount']['currency_code'] == $currency) {
|
||||
$capture = $paypalhelper->capture_order($orderid);
|
||||
if ($capture && $capture['status'] == paypal_helper::CAPTURE_STATUS_COMPLETED) {
|
||||
$success = true;
|
||||
// Everything is correct. Let's give them what they paid for.
|
||||
try {
|
||||
$paymentid = payment_helper::save_payment($payable->get_account_id(), $component, $paymentarea,
|
||||
$itemid, (int) $USER->id, $amount, $currency, 'paypal');
|
||||
|
||||
// Store PayPal extra information.
|
||||
$record = new \stdClass();
|
||||
$record->paymentid = $paymentid;
|
||||
$record->pp_orderid = $orderid;
|
||||
|
||||
$DB->insert_record('paygw_paypal', $record);
|
||||
|
||||
payment_helper::deliver_order($component, $paymentarea, $itemid, $paymentid, (int) $USER->id);
|
||||
} catch (\Exception $e) {
|
||||
debugging('Exception while trying to process payment: ' . $e->getMessage(), DEBUG_DEVELOPER);
|
||||
$success = false;
|
||||
$message = get_string('internalerror', 'paygw_paypal');
|
||||
}
|
||||
} else {
|
||||
$success = false;
|
||||
$message = get_string('paymentnotcleared', 'paygw_paypal');
|
||||
}
|
||||
} else {
|
||||
$success = false;
|
||||
$message = get_string('amountmismatch', 'paygw_paypal');
|
||||
}
|
||||
} else {
|
||||
$success = false;
|
||||
$message = get_string('paymentnotcleared', 'paygw_paypal');
|
||||
}
|
||||
} else {
|
||||
// Could not capture authorization!
|
||||
$success = false;
|
||||
$message = get_string('cannotfetchorderdatails', 'paygw_paypal');
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => $success,
|
||||
'message' => $message,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of method result value.
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function execute_returns() {
|
||||
return new external_function_parameters([
|
||||
'success' => new external_value(PARAM_BOOL, 'Whether everything was successful or not.'),
|
||||
'message' => new external_value(PARAM_RAW, 'Message (usually the error message).'),
|
||||
]);
|
||||
}
|
||||
}
|
89
payment/gateway/paypal/classes/gateway.php
Normal file
89
payment/gateway/paypal/classes/gateway.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?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 class for PayPal payment gateway.
|
||||
*
|
||||
* @package paygw_paypal
|
||||
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace paygw_paypal;
|
||||
|
||||
/**
|
||||
* The gateway class for PayPal payment gateway.
|
||||
*
|
||||
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class gateway extends \core_payment\gateway {
|
||||
public static function get_supported_currencies(): array {
|
||||
// See https://developer.paypal.com/docs/api/reference/currency-codes/,
|
||||
// 3-character ISO-4217: https://en.wikipedia.org/wiki/ISO_4217#Active_codes.
|
||||
return [
|
||||
'AUD', 'BRL', 'CAD', 'CHF', 'CZK', 'DKK', 'EUR', 'GBP', 'HKD', 'HUF', 'ILS', 'INR', 'JPY',
|
||||
'MXN', 'MYR', 'NOK', 'NZD', 'PHP', 'PLN', 'RUB', 'SEK', 'SGD', 'THB', 'TRY', 'TWD', 'USD'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration form for the gateway instance
|
||||
*
|
||||
* Use $form->get_mform() to access the \MoodleQuickForm instance
|
||||
*
|
||||
* @param \core_payment\form\account_gateway $form
|
||||
*/
|
||||
public static function add_configuration_to_gateway_form(\core_payment\form\account_gateway $form): void {
|
||||
$mform = $form->get_mform();
|
||||
|
||||
$mform->addElement('text', 'brandname', get_string('brandname', 'paygw_paypal'));
|
||||
$mform->setType('brandname', PARAM_TEXT);
|
||||
$mform->addHelpButton('brandname', 'brandname', 'paygw_paypal');
|
||||
|
||||
$mform->addElement('text', 'clientid', get_string('clientid', 'paygw_paypal'));
|
||||
$mform->setType('clientid', PARAM_TEXT);
|
||||
$mform->addHelpButton('clientid', 'clientid', 'paygw_paypal');
|
||||
|
||||
$mform->addElement('text', 'secret', get_string('secret', 'paygw_paypal'));
|
||||
$mform->setType('secret', PARAM_TEXT);
|
||||
$mform->addHelpButton('secret', 'secret', 'paygw_paypal');
|
||||
|
||||
$options = [
|
||||
'live' => get_string('live', 'paygw_paypal'),
|
||||
'sandbox' => get_string('sandbox', 'paygw_paypal'),
|
||||
];
|
||||
|
||||
$mform->addElement('select', 'environment', get_string('environment', 'paygw_paypal'), $options);
|
||||
$mform->addHelpButton('environment', 'environment', 'paygw_paypal');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the gateway configuration form.
|
||||
*
|
||||
* @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 &&
|
||||
(empty($data->brandname) || empty($data->clientid) || empty($data->secret))) {
|
||||
$errors['enabled'] = get_string('gatewaycannotbeenabled', 'payment');
|
||||
}
|
||||
}
|
||||
}
|
196
payment/gateway/paypal/classes/paypal_helper.php
Normal file
196
payment/gateway/paypal/classes/paypal_helper.php
Normal file
@ -0,0 +1,196 @@
|
||||
<?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 to work with PayPal REST API.
|
||||
*
|
||||
* @package core_payment
|
||||
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace paygw_paypal;
|
||||
|
||||
use curl;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/filelib.php');
|
||||
|
||||
class paypal_helper {
|
||||
|
||||
/**
|
||||
* @var string The payment was authorized or the authorized payment was captured for the order.
|
||||
*/
|
||||
public const CAPTURE_STATUS_COMPLETED = 'COMPLETED';
|
||||
|
||||
/**
|
||||
* @var string The merchant intends to capture payment immediately after the customer makes a payment.
|
||||
*/
|
||||
public const ORDER_INTENT_CAPTURE = 'CAPTURE';
|
||||
|
||||
/**
|
||||
* @var string The customer approved the payment.
|
||||
*/
|
||||
public const ORDER_STATUS_APPROVED = 'APPROVED';
|
||||
|
||||
/**
|
||||
* @var string The base API URL
|
||||
*/
|
||||
private $baseurl;
|
||||
|
||||
/**
|
||||
* @var string Client ID
|
||||
*/
|
||||
private $clientid;
|
||||
|
||||
/**
|
||||
* @var string PayPal App secret
|
||||
*/
|
||||
private $secret;
|
||||
|
||||
/**
|
||||
* @var string The oath bearer token
|
||||
*/
|
||||
private $token;
|
||||
|
||||
/**
|
||||
* helper constructor.
|
||||
*
|
||||
* @param string $clientid The client id.
|
||||
* @param string $secret PayPal secret.
|
||||
* @param bool $sandbox Whether we are working with the sandbox environment or not.
|
||||
*/
|
||||
public function __construct(string $clientid, string $secret, bool $sandbox) {
|
||||
$this->clientid = $clientid;
|
||||
$this->secret = $secret;
|
||||
$this->baseurl = $sandbox ? 'https://api.sandbox.paypal.com' : 'https://api.paypal.com';
|
||||
|
||||
$this->token = $this->get_token();
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures an authorized payment, by ID.
|
||||
*
|
||||
* @param string $authorizationid The PayPal-generated ID for the authorized payment to capture.
|
||||
* @param float $amount The amount to capture.
|
||||
* @param string $currency The currency code for the amount.
|
||||
* @param bool $final Indicates whether this is the final captures against the authorized payment.
|
||||
* @return array|null Formatted API response.
|
||||
*/
|
||||
public function capture_authorization(string $authorizationid, float $amount, string $currency, bool $final = true): ?array {
|
||||
$location = "{$this->baseurl}/v2/payments/authorizations/{$authorizationid}/capture";
|
||||
|
||||
$options = [
|
||||
'CURLOPT_RETURNTRANSFER' => true,
|
||||
'CURLOPT_TIMEOUT' => 30,
|
||||
'CURLOPT_HTTP_VERSION' => CURL_HTTP_VERSION_1_1,
|
||||
'CURLOPT_SSLVERSION' => CURL_SSLVERSION_TLSv1_2,
|
||||
'CURLOPT_HTTPHEADER' => [
|
||||
'Content-Type: application/json',
|
||||
"Authorization: Bearer {$this->token}",
|
||||
],
|
||||
];
|
||||
|
||||
$command = [
|
||||
'amount' => [
|
||||
'value' => (string) $amount,
|
||||
'currency_code' => $currency,
|
||||
],
|
||||
'final_capture' => $final,
|
||||
];
|
||||
$command = json_encode($command);
|
||||
|
||||
$curl = new curl();
|
||||
$result = $curl->post($location, $command, $options);
|
||||
|
||||
return json_decode($result, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures order details from PayPal.
|
||||
*
|
||||
* @param string $orderid The order we want to capture.
|
||||
* @return array|null Formatted API response.
|
||||
*/
|
||||
public function capture_order(string $orderid): ?array {
|
||||
$location = "{$this->baseurl}/v2/checkout/orders/{$orderid}/capture";
|
||||
|
||||
$options = [
|
||||
'CURLOPT_RETURNTRANSFER' => true,
|
||||
'CURLOPT_TIMEOUT' => 30,
|
||||
'CURLOPT_HTTP_VERSION' => CURL_HTTP_VERSION_1_1,
|
||||
'CURLOPT_SSLVERSION' => CURL_SSLVERSION_TLSv1_2,
|
||||
'CURLOPT_HTTPHEADER' => [
|
||||
'Content-Type: application/json',
|
||||
"Authorization: Bearer {$this->token}",
|
||||
],
|
||||
];
|
||||
|
||||
$command = '{}';
|
||||
|
||||
$curl = new curl();
|
||||
$result = $curl->post($location, $command, $options);
|
||||
|
||||
return json_decode($result, true);
|
||||
}
|
||||
|
||||
public function get_order_details(string $orderid): ?array {
|
||||
$location = "{$this->baseurl}/v2/checkout/orders/{$orderid}";
|
||||
|
||||
$options = [
|
||||
'CURLOPT_RETURNTRANSFER' => true,
|
||||
'CURLOPT_TIMEOUT' => 30,
|
||||
'CURLOPT_HTTP_VERSION' => CURL_HTTP_VERSION_1_1,
|
||||
'CURLOPT_SSLVERSION' => CURL_SSLVERSION_TLSv1_2,
|
||||
'CURLOPT_HTTPHEADER' => [
|
||||
'Content-Type: application/json',
|
||||
"Authorization: Bearer {$this->token}",
|
||||
],
|
||||
];
|
||||
|
||||
$curl = new curl();
|
||||
$result = $curl->get($location, [], $options);
|
||||
|
||||
return json_decode($result, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request for PayPal REST oath bearer token.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_token(): string {
|
||||
$location = "{$this->baseurl}/v1/oauth2/token";
|
||||
|
||||
$options = [
|
||||
'CURLOPT_RETURNTRANSFER' => true,
|
||||
'CURLOPT_TIMEOUT' => 30,
|
||||
'CURLOPT_HTTP_VERSION' => CURL_HTTP_VERSION_1_1,
|
||||
'CURLOPT_SSLVERSION' => CURL_SSLVERSION_TLSv1_2,
|
||||
'CURLOPT_USERPWD' => "{$this->clientid}:{$this->secret}",
|
||||
];
|
||||
|
||||
$command = 'grant_type=client_credentials';
|
||||
|
||||
$curl = new curl();
|
||||
$result = $curl->post($location, $command, $options);
|
||||
|
||||
$result = json_decode($result, true);
|
||||
|
||||
return $result['access_token'];
|
||||
}
|
||||
}
|
82
payment/gateway/paypal/classes/privacy/provider.php
Normal file
82
payment/gateway/paypal/classes/privacy/provider.php
Normal file
@ -0,0 +1,82 @@
|
||||
<?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 paygw_paypal.
|
||||
*
|
||||
* @package paygw_paypal
|
||||
* @category privacy
|
||||
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace paygw_paypal\privacy;
|
||||
|
||||
use core_payment\privacy\paygw_provider;
|
||||
use core_privacy\local\request\writer;
|
||||
|
||||
/**
|
||||
* Privacy Subsystem implementation for paygw_paypal.
|
||||
*
|
||||
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class provider implements \core_privacy\local\metadata\null_provider, paygw_provider {
|
||||
|
||||
/**
|
||||
* Get the language string identifier with the component's language
|
||||
* file to explain why this plugin stores no data.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_reason() : string {
|
||||
return 'privacy:metadata';
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
global $DB;
|
||||
|
||||
$subcontext[] = get_string('gatewayname', 'paygw_paypal');
|
||||
$record = $DB->get_record('paygw_paypal', ['paymentid' => $payment->id]);
|
||||
|
||||
$data = (object) [
|
||||
'orderid' => $record->pp_orderid,
|
||||
];
|
||||
writer::with_context($context)->export_data(
|
||||
$subcontext,
|
||||
$data
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
$DB->delete_records_select('paygw_paypal', "paymentid IN ({$paymentsql})", $paymentparams);
|
||||
}
|
||||
}
|
29
payment/gateway/paypal/db/install.php
Normal file
29
payment/gateway/paypal/db/install.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* paygw_paypal installer script.
|
||||
*
|
||||
* @package paygw_paypal
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
function xmldb_paygw_paypal_install() {
|
||||
// Enable the Paypal payment gateway on installation. It still needs to be configured and enabled for accounts.
|
||||
$order = (!empty($CFG->paygw_plugins_sortorder)) ? explode(',', $CFG->paygw_plugins_sortorder) : [];
|
||||
set_config('paygw_plugins_sortorder', join(',', array_merge($order, ['paypal'])));
|
||||
}
|
19
payment/gateway/paypal/db/install.xml
Executable file
19
payment/gateway/paypal/db/install.xml
Executable file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<XMLDB PATH="payment/gateway/paypal/db" VERSION="20200110" COMMENT="XMLDB file for PayPal payment gateway plugin"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../../../lib/xmldb/xmldb.xsd"
|
||||
>
|
||||
<TABLES>
|
||||
<TABLE NAME="paygw_paypal" COMMENT="Stores PayPal related information">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="paymentid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="pp_orderid" TYPE="char" LENGTH="255" NOTNULL="true" DEFAULT="The ID of the order in PayPal" SEQUENCE="false"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
<KEY NAME="paymentid" TYPE="foreign-unique" FIELDS="paymentid" REFTABLE="payment" REFFIELDS="id"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
</TABLES>
|
||||
</XMLDB>
|
45
payment/gateway/paypal/db/services.php
Normal file
45
payment/gateway/paypal/db/services.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* External functions and service definitions for the PayPal payment gateway plugin.
|
||||
*
|
||||
* @package paygw_paypal
|
||||
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$functions = [
|
||||
'paygw_paypal_get_config_for_js' => [
|
||||
'classname' => 'paygw_paypal\external\get_config_for_js',
|
||||
'methodname' => 'execute',
|
||||
'classpath' => '',
|
||||
'description' => 'Returns the configuration settings to be used in js',
|
||||
'type' => 'read',
|
||||
'ajax' => true,
|
||||
],
|
||||
'paygw_paypal_create_transaction_complete' => [
|
||||
'classname' => 'paygw_paypal\external\transaction_complete',
|
||||
'methodname' => 'execute',
|
||||
'classpath' => '',
|
||||
'description' => 'Takes care of what needs to be done when a PayPal transaction comes back as complete.',
|
||||
'type' => 'write',
|
||||
'ajax' => true,
|
||||
'loginrequired' => false,
|
||||
],
|
||||
];
|
45
payment/gateway/paypal/lang/en/paygw_paypal.php
Normal file
45
payment/gateway/paypal/lang/en/paygw_paypal.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Strings for component 'paygw_paypal', language 'en'
|
||||
*
|
||||
* @package paygw_paypal
|
||||
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['amountmismatch'] = 'The amount you attempted to pay does not match the required fee. Your account has not been debited.';
|
||||
$string['authorising'] = 'Authorising the payment. Please wait...';
|
||||
$string['brandname'] = 'Brand name';
|
||||
$string['brandname_help'] = 'An optional label that overrides the business name for the PayPal account on the PayPal site.';
|
||||
$string['cannotfetchorderdatails'] = 'Could not fetch payment details from PayPal. Your account has not been debited.';
|
||||
$string['clientid'] = 'Client ID';
|
||||
$string['clientid_help'] = 'The client ID that PayPal generated for your application.';
|
||||
$string['environment'] = 'Environment';
|
||||
$string['environment_help'] = 'You can set this to Sandbox if you are using sandbox accounts (for testing purpose only).';
|
||||
$string['gatewaydescription'] = 'PayPal is an authorised payment gateway provider for processing credit card transactions.';
|
||||
$string['gatewayname'] = 'PayPal';
|
||||
$string['internalerror'] = 'An internal error has occurred. Please contact us.';
|
||||
$string['live'] = 'Live';
|
||||
$string['paymentnotcleared'] = 'payment not cleared by PayPal.';
|
||||
$string['pluginname'] = 'PayPal';
|
||||
$string['pluginname_desc'] = 'The PayPal plugin allows you to receive payments via PayPal.';
|
||||
$string['privacy:metadata'] = 'The Analytic models plugin does not store any personal data.';
|
||||
$string['repeatedorder'] = 'This order has already been processed earlier.';
|
||||
$string['sandbox'] = 'Sandbox';
|
||||
$string['secret'] = 'Secret';
|
||||
$string['secret_help'] = 'The secret thatPayPal generated for your application.';
|
330
payment/gateway/paypal/pix/img.svg
Normal file
330
payment/gateway/paypal/pix/img.svg
Normal file
@ -0,0 +1,330 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 320 125" style="enable-background:new 0 0 320 125;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:url(#SVGID_1_);}
|
||||
.st1{fill:#222562;}
|
||||
.st2{fill-rule:evenodd;clip-rule:evenodd;fill:#FF8000;}
|
||||
.st3{fill-rule:evenodd;clip-rule:evenodd;fill:#FF0000;}
|
||||
|
||||
.st4{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;stroke:#FFFFFF;stroke-width:0.1212;stroke-linecap:square;stroke-miterlimit:10;}
|
||||
.st5{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
|
||||
.st6{fill:none;stroke:#FFFFFF;stroke-width:0.1212;stroke-linecap:square;stroke-miterlimit:10;}
|
||||
.st7{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;stroke:#999999;}
|
||||
.st8{fill-rule:evenodd;clip-rule:evenodd;fill:#E6E7E8;stroke:#000000;}
|
||||
.st9{fill:#263F6B;stroke:#263F6B;stroke-width:0.25;}
|
||||
.st10{fill-rule:evenodd;clip-rule:evenodd;fill:#009DE2;}
|
||||
.st11{fill-rule:evenodd;clip-rule:evenodd;fill:#113984;}
|
||||
.st12{fill-rule:evenodd;clip-rule:evenodd;fill:#172C70;}
|
||||
.st13{fill:#00589F;}
|
||||
.st14{fill:#F9A51A;}
|
||||
.st15{fill:#F79739;stroke:#F79739;stroke-width:6;}
|
||||
.st16{fill:none;stroke:#F79739;stroke-width:2;}
|
||||
</style>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="159.3737" y1="31.3265" x2="159.3737" y2="121.832">
|
||||
<stop offset="0" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.2032" style="stop-color:#FFFEFC"/>
|
||||
<stop offset="0.35" style="stop-color:#FFFAF3"/>
|
||||
<stop offset="0.479" style="stop-color:#FEF4E3"/>
|
||||
<stop offset="0.5978" style="stop-color:#FEEBCD"/>
|
||||
<stop offset="0.7097" style="stop-color:#FDDFB0"/>
|
||||
<stop offset="0.8164" style="stop-color:#FDD18C"/>
|
||||
<stop offset="0.917" style="stop-color:#FCC063"/>
|
||||
<stop offset="1" style="stop-color:#FBB03B"/>
|
||||
</linearGradient>
|
||||
<rect x="4.6" y="31.3" class="st0" width="309.5" height="90.5"/>
|
||||
<g>
|
||||
<rect x="120.8" y="62" class="st1" width="78.6" height="47.7"/>
|
||||
<g>
|
||||
<polygon class="st2" points="174.1,64.3 175.2,64.3 176.3,64.4 178.4,64.8 180.5,65.3 182.5,66 184.4,66.9 186.2,68 187.8,69.3
|
||||
189.4,70.6 190.8,72.2 192,73.8 193.1,75.6 194,77.5 194.7,79.4 195.3,81.5 195.6,83.7 195.7,85.8 195.7,86.9 195.6,88
|
||||
195.3,90.1 194.7,92.2 194,94.2 193.1,96.1 192,97.8 190.8,99.5 189.4,101 187.8,102.4 186.2,103.7 184.4,104.7 182.5,105.7
|
||||
180.5,106.4 178.4,106.9 176.3,107.2 174.1,107.3 173,107.3 171.9,107.2 169.8,106.9 167.8,106.4 165.8,105.7 163.9,104.8
|
||||
162.2,103.7 160.5,102.4 159,101 157.6,99.5 156.4,97.9 155.4,96.1 154.5,94.2 153.8,92.3 153.2,90.2 152.9,88.1 152.8,85.9
|
||||
152.8,84.8 152.9,83.7 153.2,81.6 153.8,79.5 154.5,77.5 155.4,75.7 156.4,73.9 157.6,72.2 159,70.7 160.5,69.3 162.2,68
|
||||
163.9,66.9 165.8,66 167.8,65.3 169.8,64.8 171.9,64.4 174.1,64.3 "/>
|
||||
<polygon class="st3" points="160.8,100.8 160.7,100.9 160.6,101 160.5,101.1 160.4,101.2 160.3,101.3 160.2,101.3 160.1,101.4
|
||||
160,101.5 159.9,101.6 159.9,101.7 159.8,101.8 159.7,101.8 159.6,101.9 159.5,102 159.4,102.1 159.3,102.2 158.9,102.5
|
||||
158.5,102.7 157.8,103.3 157,103.8 156.3,104.2 155.4,104.7 154.6,105.1 153.8,105.5 152.9,105.8 152.1,106.1 151.2,106.3
|
||||
150.3,106.5 149.4,106.7 148.5,106.9 147.6,107 146.7,107 145.8,107.1 144.7,107 143.6,106.9 141.5,106.6 139.5,106.1
|
||||
137.5,105.4 135.7,104.5 133.9,103.4 132.3,102.2 130.8,100.8 129.4,99.3 128.2,97.7 127.1,95.9 126.2,94.1 125.5,92.1 125,90.1
|
||||
124.6,88 124.5,85.9 124.5,84.8 124.6,83.7 125,81.6 125.5,79.6 126.3,77.7 127.2,75.8 128.3,74.1 129.5,72.4 130.9,70.9
|
||||
132.4,69.6 134.1,68.4 135.7,67.3 137.5,66.4 139.4,65.7 141.3,65.2 143.2,64.9 145.1,64.8 145.7,64.8 146.2,64.8 147.3,64.9
|
||||
148.3,65 149.3,65.2 150.3,65.4 151.2,65.6 152.1,65.8 153,66.1 153.9,66.5 154.7,66.8 155.5,67.2 156.2,67.6 157,68.1
|
||||
157.7,68.5 158.4,69 159,69.5 159.7,70.2 160.5,70.9 161.3,71.8 158,71.8 157.1,72.9 162.5,72.9 162.7,73.2 163.3,74 163.5,74.3
|
||||
156.2,74.3 155.5,75.4 164.2,75.4 164.4,75.8 165,76.8 154.8,76.8 154.3,78 165.4,78 165.7,78.6 166,79.4 153.8,79.4 153.5,80.5
|
||||
166.3,80.5 166.6,81.6 166.7,81.9 153.2,81.9 153,83 166.8,83 166.9,83.7 167,84.8 167,85.9 167,87 163.5,87 163.5,88.1
|
||||
166.9,88.1 166.8,89.1 166.7,89.5 163.2,89.5 163.1,90.7 166.5,90.7 166.4,91.1 166.1,92.1 153.7,92.1 154.1,93.2 165.7,93.2
|
||||
165.4,94.1 165.1,94.6 154.7,94.6 155.2,95.7 164.5,95.7 164.4,95.9 163.9,96.8 163.7,97.1 156,97.1 156.7,98.3 163,98.3
|
||||
162.8,98.5 162.1,99.3 161.8,99.7 157.7,99.7 158.8,100.8 160.8,100.8 "/>
|
||||
<polygon class="st2" points="154.7,87 152,87 152.1,88 154.7,88 154.7,87 "/>
|
||||
<polygon class="st4" points="173.1,83.9 173.1,83.9 172.9,83.8 172.8,83.8 172.6,83.7 172.5,83.7 172.4,83.6 172.2,83.6
|
||||
172.1,83.6 171.9,83.5 171.8,83.5 171.7,83.5 171.5,83.5 171.3,83.5 171,83.5 170.9,83.5 170.7,83.5 170.6,83.5 170.3,83.6
|
||||
170.1,83.7 169.8,83.8 169.6,83.9 169.4,84.1 169.2,84.3 169,84.5 168.9,84.7 168.7,85 168.6,85.2 168.5,85.5 168.4,85.8
|
||||
168.3,86.1 168.2,86.4 168.2,86.6 168.1,86.8 168.1,86.9 168.1,87.2 168.2,87.5 168.2,87.8 168.3,88 168.4,88.2 168.6,88.5
|
||||
168.7,88.7 168.9,88.8 169.1,89 169.3,89.1 169.5,89.3 169.7,89.3 170,89.4 170.2,89.4 170.5,89.4 170.6,89.4 170.7,89.4
|
||||
170.9,89.4 171,89.4 171.2,89.4 171.3,89.3 171.5,89.3 171.6,89.3 171.7,89.3 171.9,89.2 172,89.2 172.1,89.1 172.1,89.1
|
||||
172.2,89.1 172.3,89 172.4,89 172.5,89.1 172.4,89.2 172.4,89.3 172.4,89.4 172.3,89.4 172.3,89.5 172.3,89.6 172.2,89.7
|
||||
172.2,89.8 172.2,89.9 172.1,90 172.1,90.1 172.1,90.2 172.1,90.3 172.1,90.4 172.1,90.5 172.1,90.7 172.1,90.8 172.1,90.9
|
||||
172.1,90.9 172,91 171.9,91 171.8,91 171.7,91.1 171.6,91.1 171.4,91.1 171.3,91.1 171.2,91.2 171.1,91.2 171,91.2 170.9,91.2
|
||||
170.8,91.2 170.6,91.2 170.1,91.2 169.8,91.2 169.3,91.1 168.9,91 168.4,90.9 168,90.7 167.7,90.5 167.4,90.3 167.1,90
|
||||
166.8,89.7 166.6,89.4 166.5,89 166.3,88.6 166.2,88.2 166.2,87.7 166.2,87.3 166.2,86.8 166.2,86.4 166.2,86.1 166.3,85.5
|
||||
166.5,85 166.7,84.5 166.9,84 167.2,83.6 167.4,83.2 167.8,82.9 168.1,82.6 168.5,82.3 168.9,82.1 169.3,81.9 169.7,81.8
|
||||
170.2,81.7 170.6,81.6 171.1,81.6 171.2,81.7 171.3,81.7 171.5,81.7 171.7,81.7 171.8,81.7 172,81.7 172.2,81.8 172.3,81.8
|
||||
172.5,81.8 172.6,81.8 172.8,81.9 172.9,81.9 173,81.9 173.2,82 173.3,82 173.4,82.1 173.5,82.1 173.5,82.2 173.5,82.3
|
||||
173.5,82.4 173.5,82.5 173.5,82.6 173.5,82.6 173.4,82.7 173.4,82.8 173.4,82.8 173.4,82.9 173.4,83 173.4,83 173.4,83.2
|
||||
173.3,83.3 173.3,83.3 173.3,83.4 173.3,83.5 173.3,83.6 173.3,83.7 173.3,83.7 173.3,83.8 173.3,83.9 173.2,83.9 173.1,83.9
|
||||
"/>
|
||||
<polygon class="st4" points="162.3,83.5 164.2,83.5 164.1,84.4 164.1,84.5 164.1,84.6 164.2,84.6 164.3,84.6 164.3,84.5
|
||||
164.4,84.4 164.5,84.3 164.6,84.2 164.7,84 164.8,83.9 165,83.8 165.1,83.8 165.2,83.7 165.4,83.6 165.5,83.6 165.7,83.6
|
||||
165.8,83.5 166,83.5 166.1,83.5 166.3,83.5 166.5,83.5 165.9,84.7 165.7,85.6 165.6,85.5 165.5,85.5 165.4,85.5 165.2,85.5
|
||||
165.1,85.5 164.9,85.6 164.8,85.6 164.6,85.7 164.5,85.8 164.4,85.9 164.3,86 164.2,86.1 164.1,86.3 164,86.5 163.9,86.7
|
||||
163.8,86.9 163.8,87.1 163.2,90.1 163.1,91.1 160.9,91.1 161.2,90 162.2,84.2 162.3,83.5 "/>
|
||||
<polygon class="st4" points="144.2,91 144.3,90.1 144.4,89.4 144.4,89.4 144.5,89.4 144.6,89.5 144.8,89.5 145,89.5 145.1,89.6
|
||||
145.4,89.6 145.5,89.6 145.8,89.6 145.9,89.6 146.1,89.6 146.3,89.6 146.5,89.6 147.1,89.6 147.1,89.6 147.3,89.6 147.4,89.6
|
||||
147.5,89.5 147.6,89.4 147.7,89.3 147.8,89.2 147.8,89.1 147.9,89 147.9,88.8 147.8,88.7 147.8,88.6 147.7,88.5 147.6,88.4
|
||||
147.4,88.2 147.2,88.1 147.1,88.1 147,88 146.8,88 146.6,87.9 146.4,87.8 146.2,87.7 146,87.6 145.8,87.5 145.6,87.3 145.5,87.2
|
||||
145.3,87 145.2,86.9 145.1,86.7 145,86.5 145,86.2 145,86 145,85.7 145,85.6 145,85.5 145,85.3 145.1,85 145.2,84.9 145.3,84.7
|
||||
145.4,84.5 145.5,84.3 145.6,84.1 145.8,84 146,83.8 146.2,83.7 146.5,83.6 146.7,83.5 147,83.5 147.3,83.4 147.7,83.4 148,83.4
|
||||
148.2,83.4 148.4,83.4 148.6,83.4 148.7,83.4 148.9,83.4 149,83.5 149.2,83.5 149.4,83.5 149.5,83.5 149.7,83.5 149.8,83.5
|
||||
150,83.5 150.2,83.5 150.3,83.5 150,84.6 149.9,85.1 149.8,85.1 149.8,85.1 149.6,85 149.5,85 149.3,85 149.2,85 149,85 148.8,85
|
||||
148.7,85 148.5,84.9 147.9,84.9 147.8,85 147.7,85 147.6,85 147.6,85 147.4,85.1 147.4,85.1 147.3,85.2 147.2,85.3 147.2,85.4
|
||||
147.1,85.4 147.1,85.5 147.1,85.6 147.1,85.7 147.2,85.8 147.2,85.9 147.3,86 147.4,86.1 147.5,86.2 147.7,86.3 147.8,86.4
|
||||
147.9,86.4 148.1,86.5 148.3,86.6 148.5,86.7 148.7,86.8 148.9,86.9 149.1,87 149.3,87.2 149.4,87.3 149.5,87.5 149.7,87.7
|
||||
149.8,87.9 149.8,88.1 149.9,88.4 149.9,88.7 149.8,89 149.8,89.2 149.8,89.3 149.7,89.6 149.6,89.9 149.5,90.1 149.4,90.3
|
||||
149.3,90.4 149.1,90.6 148.9,90.7 148.7,90.8 148.5,90.9 148.3,91 148,91 147.8,91.1 147.5,91.1 147.2,91.1 146.9,91.2
|
||||
146.8,91.2 146.6,91.2 146.5,91.2 146.3,91.2 146,91.2 145.8,91.2 145.6,91.2 145.5,91.2 145.3,91.2 145.1,91.1 144.9,91.1
|
||||
144.7,91.1 144.6,91.1 144.4,91 144.2,91 "/>
|
||||
<polygon class="st4" points="128.4,81.7 131.7,81.7 131.8,87.8 132,87.8 134.5,81.7 137.9,81.7 137.6,82.9 136.3,90.1 136.3,91.1
|
||||
134.2,91.1 134.5,90 135.6,83.5 135.4,83.5 132.2,91.1 130.5,91.1 129.9,83.5 129.8,83.5 128.6,90 128.5,91.1 126.6,91.1
|
||||
126.9,90.1 128.3,82.5 128.4,81.7 "/>
|
||||
<polygon class="st5" points="191,81.7 190.6,84.3 190.5,84.4 190.4,84.5 190.3,84.4 190.3,84.3 190.2,84.2 190.1,84.1 190,84
|
||||
189.9,83.9 189.8,83.9 189.7,83.8 189.7,83.8 189.6,83.8 189.5,83.7 189.4,83.7 189.3,83.6 189.2,83.6 189.2,83.6 189.1,83.5
|
||||
189,83.5 188.9,83.5 188.9,83.5 188.8,83.5 188.6,83.4 188.5,83.4 188.2,83.4 187.8,83.5 187.5,83.5 187.2,83.6 186.9,83.8
|
||||
186.6,83.9 186.3,84.1 186.1,84.3 185.8,84.6 185.6,84.9 185.4,85.1 185.2,85.5 185,85.8 184.9,86.2 184.8,86.6 184.8,86.9
|
||||
184.7,87.1 184.7,87.6 184.6,88 184.7,88.4 184.7,88.8 184.8,89.1 184.9,89.5 185,89.8 185.2,90 185.4,90.3 185.6,90.5
|
||||
185.8,90.7 186.1,90.8 186.4,91 186.7,91.1 187,91.1 187.1,91.2 187.3,91.2 187.5,91.2 187.7,91.1 187.9,91.1 188.1,91 188.2,91
|
||||
188.4,90.9 188.6,90.8 188.7,90.8 188.9,90.7 189,90.6 189.1,90.5 189.2,90.4 189.3,90.3 189.4,90.2 189.4,90.2 189.5,90.3
|
||||
189.4,91.1 191.5,91.1 191.6,90.3 192.5,85.1 188.5,85.1 188.8,85.1 188.9,85.2 189,85.2 189.3,85.3 189.5,85.4 189.6,85.5
|
||||
189.7,85.6 189.8,85.8 189.9,85.9 190,86.1 190,86.3 190,86.5 190,86.7 190,86.9 190,87.1 189.9,87.3 189.9,87.5 189.9,87.7
|
||||
189.8,87.8 189.8,87.9 189.7,88.1 189.6,88.3 189.5,88.5 189.5,88.7 189.3,88.8 189.2,88.9 189.1,89.1 189,89.2 188.9,89.3
|
||||
188.7,89.3 188.6,89.4 188.4,89.4 188.2,89.4 188.1,89.5 187.8,89.5 187.7,89.4 187.6,89.4 187.4,89.3 187.3,89.3 187.2,89.2
|
||||
187.1,89.1 187,88.9 186.9,88.8 186.8,88.6 186.8,88.5 186.7,88.3 186.7,88.1 186.7,87.9 186.7,87.7 186.7,87.4 186.7,87.2
|
||||
186.8,87.1 186.8,87 186.8,86.8 186.9,86.6 187,86.4 187.1,86.2 187.2,86.1 187.3,85.9 187.4,85.7 187.5,85.6 187.7,85.5
|
||||
187.8,85.4 188,85.3 188.2,85.2 188.4,85.2 188.5,85.1 192.5,85.1 192.9,82.9 193.2,81.7 191,81.7 "/>
|
||||
<polygon class="st5" points="181.2,83.5 183.2,83.5 183,84.4 183,84.5 183,84.6 183.1,84.6 183.2,84.6 183.2,84.5 183.3,84.4
|
||||
183.4,84.3 183.5,84.2 183.7,84.1 183.8,84 183.9,83.9 184,83.8 184.2,83.8 184.3,83.7 184.5,83.6 184.6,83.6 184.8,83.5
|
||||
184.9,83.5 185.1,83.5 185.3,83.5 185.4,83.5 184.9,84.7 184.7,85.6 184.6,85.5 184.6,85.5 184.4,85.5 184.2,85.5 184.1,85.5
|
||||
183.9,85.6 183.8,85.6 183.6,85.7 183.5,85.8 183.4,85.9 183.2,86 183.1,86.1 183,86.3 182.9,86.5 182.8,86.7 182.8,86.9
|
||||
182.7,87.1 182.2,90.1 182,91.1 179.9,91.1 180.1,90 181.2,84.2 181.2,83.5 "/>
|
||||
<polyline class="st6" points="191,81.7 190.6,84.3 190.5,84.4 190.4,84.5 190.3,84.4 190.3,84.3 190.2,84.2 190.1,84.1 190,84
|
||||
189.9,83.9 189.8,83.9 189.7,83.8 189.7,83.8 189.6,83.8 189.5,83.7 189.4,83.7 189.3,83.6 189.2,83.6 189.2,83.6 189.1,83.5
|
||||
189,83.5 188.9,83.5 188.9,83.5 188.8,83.5 188.6,83.4 188.5,83.4 188.2,83.4 187.8,83.5 187.5,83.5 187.2,83.6 186.9,83.8
|
||||
186.6,83.9 186.3,84.1 186.1,84.3 185.8,84.6 185.6,84.9 185.4,85.1 185.2,85.5 185,85.8 184.9,86.2 184.8,86.6 184.8,86.9
|
||||
184.7,87.1 184.7,87.6 184.6,88 184.7,88.4 184.7,88.8 184.8,89.1 184.9,89.5 185,89.8 185.2,90 185.4,90.3 185.6,90.5
|
||||
185.8,90.7 186.1,90.8 186.4,91 186.7,91.1 187,91.1 187.1,91.2 187.3,91.2 "/>
|
||||
<polyline class="st6" points="187.3,91.2 187.5,91.2 187.7,91.1 187.9,91.1 188.1,91 188.2,91 188.4,90.9 188.6,90.8 188.7,90.8
|
||||
188.9,90.7 189,90.6 189.1,90.5 189.2,90.4 189.3,90.3 189.4,90.2 189.4,90.2 189.5,90.3 189.4,91.1 191.5,91.1 191.6,90.3
|
||||
192.9,82.9 193.2,81.7 191,81.7 "/>
|
||||
<polyline class="st6" points="181.2,83.5 183.2,83.5 183,84.4 183,84.5 183,84.6 183.1,84.6 183.2,84.6 183.2,84.5 183.3,84.4
|
||||
183.4,84.3 183.5,84.2 183.7,84.1 183.8,84 183.9,83.9 184,83.8 184.2,83.8 184.3,83.7 184.5,83.6 184.6,83.6 184.8,83.5
|
||||
184.9,83.5 185.1,83.5 185.3,83.5 185.4,83.5 184.9,84.7 184.7,85.6 184.6,85.5 184.6,85.5 184.4,85.5 184.2,85.5 184.1,85.5
|
||||
183.9,85.6 183.8,85.6 183.6,85.7 183.5,85.8 183.4,85.9 183.2,86 183.1,86.1 183,86.3 182.9,86.5 182.8,86.7 182.8,86.9
|
||||
182.7,87.1 182.2,90.1 182,91.1 179.9,91.1 180.1,90 181.2,84.2 181.2,83.5 "/>
|
||||
<polyline class="st6" points="189.9,87.7 189.8,87.8 189.8,87.9 189.7,88.1 189.6,88.3 189.5,88.5 189.5,88.7 189.3,88.8
|
||||
189.2,88.9 189.1,89.1 189,89.2 188.9,89.3 188.7,89.3 188.6,89.4 188.4,89.4 188.2,89.4 188.1,89.5 187.8,89.5 187.7,89.4
|
||||
187.6,89.4 187.4,89.3 187.3,89.3 187.2,89.2 187.1,89.1 187,88.9 186.9,88.8 186.8,88.6 186.8,88.5 186.7,88.3 186.7,88.1
|
||||
186.7,87.9 186.7,87.7 186.7,87.4 186.7,87.2 186.8,87.1 186.8,87 186.8,86.8 186.9,86.6 187,86.4 187.1,86.2 187.2,86.1
|
||||
187.3,85.9 187.4,85.7 187.5,85.6 187.7,85.5 187.8,85.4 188,85.3 188.2,85.2 188.4,85.2 188.5,85.1 188.8,85.1 188.9,85.2
|
||||
189,85.2 189.3,85.3 189.5,85.4 189.6,85.5 189.7,85.6 189.8,85.8 189.9,85.9 190,86.1 "/>
|
||||
<polyline class="st6" points="190,86.1 190,86.3 190,86.5 190,86.7 190,86.9 190,87.1 189.9,87.3 189.9,87.5 189.9,87.7 "/>
|
||||
<polygon class="st5" points="141.5,90.3 141.5,90.3 141.3,90.5 141.2,90.6 141.1,90.6 141,90.7 140.9,90.8 140.8,90.9 140.7,90.9
|
||||
140.5,91 140.4,91 140.2,91.1 140.1,91.1 139.9,91.2 139.7,91.2 139.6,91.2 139.4,91.2 139.2,91.2 139.1,91.2 138.8,91.2
|
||||
138.5,91.1 138.3,91 138.1,90.8 137.9,90.7 137.7,90.5 137.6,90.4 137.5,90.2 137.4,90 137.3,89.8 137.3,89.5 137.2,89.3
|
||||
137.2,89.1 137.2,88.9 137.3,88.7 137.3,88.5 137.3,88.3 137.5,88 137.6,87.7 137.8,87.5 138,87.2 138.2,87 138.4,86.8
|
||||
138.8,86.7 139.1,86.5 139.4,86.4 139.8,86.3 140.3,86.3 140.7,86.2 141.2,86.2 141.8,86.2 142.4,86.2 142.4,86.1 142.4,86
|
||||
142.4,85.9 142.4,85.7 142.3,85.6 142.3,85.5 142.2,85.4 142.2,85.3 142.1,85.2 142,85.2 141.9,85.1 141.7,85 141.6,85
|
||||
141.5,84.9 141.4,84.9 141.2,84.9 141.1,84.9 140.7,84.9 140.6,84.9 140.4,84.9 140.2,84.9 140,84.9 139.9,84.9 139.7,85
|
||||
139.5,85 139.3,85 139.1,85.1 138.9,85.1 138.8,85.1 138.6,85.2 138.4,85.3 138.5,84.8 138.8,83.8 138.8,83.7 138.9,83.7
|
||||
139.1,83.6 139.2,83.6 139.3,83.6 139.5,83.5 139.6,83.5 139.8,83.5 140,83.5 140.2,83.4 140.4,83.4 140.7,83.4 140.9,83.4
|
||||
141.2,83.4 141.4,83.4 141.9,83.4 142,83.4 142.3,83.4 142.5,83.5 142.7,83.5 143,83.6 143.2,83.7 143.4,83.8 143.6,84
|
||||
143.8,84.1 143.9,84.3 144.1,84.5 144.2,84.7 144.2,84.9 144.3,85.1 144.3,85.4 144.3,85.6 143.9,87.5 141.3,87.5 141.2,87.5
|
||||
141,87.5 140.7,87.6 140.5,87.6 140.4,87.7 140.1,87.7 140,87.8 139.8,87.9 139.6,88 139.5,88.1 139.4,88.2 139.4,88.3
|
||||
139.3,88.4 139.3,88.5 139.2,88.7 139.2,88.8 139.2,89 139.3,89.1 139.3,89.2 139.4,89.3 139.5,89.4 139.6,89.5 139.7,89.6
|
||||
139.9,89.6 140.1,89.6 140.3,89.6 140.5,89.6 140.7,89.6 140.8,89.6 140.9,89.5 141.1,89.5 141.2,89.3 141.4,89.2 141.5,89.1
|
||||
141.6,88.9 141.7,88.8 141.8,88.6 141.9,88.5 141.9,88.3 141.9,88.1 142,88 142,87.9 142,87.7 142,87.6 141.9,87.6 141.8,87.6
|
||||
141.7,87.5 141.5,87.5 141.3,87.5 143.9,87.5 143.6,89.3 143.6,89.4 143.6,89.5 143.6,89.5 143.6,89.6 143.6,89.7 143.6,89.8
|
||||
143.5,90 143.5,90 143.5,90.2 143.5,90.3 143.5,90.4 143.5,90.5 143.5,90.8 143.5,90.9 143.5,91.1 141.6,91.1 141.7,90.3
|
||||
141.6,90.2 141.5,90.2 141.5,90.3 "/>
|
||||
<polyline class="st6" points="141.5,90.3 141.5,90.3 141.3,90.5 141.2,90.6 141.1,90.6 141,90.7 140.9,90.8 140.8,90.9
|
||||
140.7,90.9 140.5,91 140.4,91 140.2,91.1 140.1,91.1 139.9,91.2 139.7,91.2 139.6,91.2 139.4,91.2 139.2,91.2 139.1,91.2
|
||||
138.8,91.2 138.5,91.1 138.3,91 138.1,90.8 137.9,90.7 137.7,90.5 137.6,90.4 137.5,90.2 137.4,90 137.3,89.8 137.3,89.5
|
||||
137.2,89.3 137.2,89.1 137.2,88.9 137.3,88.7 137.3,88.5 137.3,88.3 137.5,88 137.6,87.7 137.8,87.5 138,87.2 138.2,87
|
||||
138.4,86.8 138.8,86.7 139.1,86.5 139.4,86.4 139.8,86.3 140.3,86.3 140.7,86.2 141.2,86.2 141.8,86.2 142.4,86.2 142.4,86.1
|
||||
142.4,86 142.4,85.9 142.4,85.7 142.3,85.6 142.3,85.5 142.2,85.4 142.2,85.3 142.1,85.2 "/>
|
||||
<polyline class="st6" points="142.1,85.2 142,85.2 141.9,85.1 141.7,85 141.6,85 141.5,84.9 141.4,84.9 141.2,84.9 141.1,84.9
|
||||
140.7,84.9 140.6,84.9 140.4,84.9 140.2,84.9 140,84.9 139.9,84.9 139.7,85 139.5,85 139.3,85 139.1,85.1 138.9,85.1 138.8,85.1
|
||||
138.6,85.2 138.4,85.3 138.5,84.8 138.8,83.8 138.8,83.7 138.9,83.7 139.1,83.6 139.2,83.6 139.3,83.6 139.5,83.5 139.6,83.5
|
||||
139.8,83.5 140,83.5 140.2,83.4 140.4,83.4 140.7,83.4 140.9,83.4 141.2,83.4 141.4,83.4 141.9,83.4 142,83.4 142.3,83.4
|
||||
142.5,83.5 142.7,83.5 143,83.6 143.2,83.7 143.4,83.8 143.6,84 143.8,84.1 143.9,84.3 144.1,84.5 144.2,84.7 144.2,84.9
|
||||
144.3,85.1 144.3,85.4 144.3,85.6 143.6,89.3 143.6,89.4 143.6,89.5 "/>
|
||||
<polyline class="st6" points="143.6,89.5 143.6,89.5 143.6,89.6 143.6,89.7 143.6,89.8 143.5,90 143.5,90 143.5,90.2 143.5,90.3
|
||||
143.5,90.4 143.5,90.5 143.5,90.8 143.5,90.9 143.5,91.1 141.6,91.1 141.7,90.3 141.6,90.2 141.5,90.2 141.5,90.3 "/>
|
||||
<polyline class="st6" points="142,87.6 141.9,87.6 141.8,87.6 141.7,87.5 141.5,87.5 141.3,87.5 141.2,87.5 141,87.5 140.7,87.6
|
||||
140.5,87.6 140.4,87.7 140.1,87.7 140,87.8 139.8,87.9 139.6,88 139.5,88.1 139.4,88.2 139.4,88.3 139.3,88.4 139.3,88.5
|
||||
139.2,88.7 139.2,88.8 139.2,89 139.3,89.1 139.3,89.2 139.4,89.3 139.5,89.4 139.6,89.5 139.7,89.6 139.9,89.6 140.1,89.6
|
||||
140.3,89.6 140.5,89.6 140.7,89.6 140.8,89.6 140.9,89.5 141.1,89.5 141.2,89.3 141.4,89.2 141.5,89.1 141.6,88.9 141.7,88.8
|
||||
141.8,88.6 141.9,88.5 141.9,88.3 141.9,88.1 142,88 142,87.9 142,87.7 142,87.6 "/>
|
||||
<polygon class="st5" points="177.2,90.4 177.1,90.4 177,90.6 176.8,90.7 176.8,90.8 176.6,90.8 176.5,90.9 176.4,91 176.3,91
|
||||
176.1,91.1 176,91.1 175.8,91.2 175.7,91.2 175.5,91.2 175.3,91.2 175.2,91.2 175,91.2 174.8,91.2 174.7,91.2 174.4,91.2
|
||||
174.1,91.1 173.9,91 173.7,90.9 173.5,90.7 173.3,90.6 173.2,90.4 173.1,90.2 173,90 172.9,89.8 172.9,89.6 172.9,89.3
|
||||
172.8,89.1 172.9,88.9 172.9,88.7 172.9,88.5 173,88.3 173.1,88 173.3,87.7 173.5,87.5 173.7,87.3 173.9,87.1 174.2,86.9
|
||||
174.5,86.8 174.8,86.7 175.2,86.6 175.6,86.5 176,86.5 176.4,86.4 176.8,86.4 177.3,86.4 177.8,86.4 177.9,86.3 177.9,86.2
|
||||
177.9,86.1 177.9,86 177.9,85.9 177.9,85.8 177.8,85.7 177.8,85.5 177.7,85.4 177.6,85.3 177.4,85.2 177.2,85.1 177,85.1
|
||||
176.8,85 176.7,85 176.3,85 176.2,85 176,85 175.8,85 175.6,85.1 175.4,85.1 175.2,85.1 175,85.1 174.8,85.2 174.6,85.2
|
||||
174.5,85.2 174.3,85.3 174.2,85.3 174,85.4 174.1,84.9 174.4,83.8 174.5,83.8 174.6,83.7 174.7,83.7 174.9,83.7 175,83.6
|
||||
175.2,83.6 175.3,83.6 175.5,83.5 175.7,83.5 175.9,83.5 176.1,83.5 176.3,83.4 176.5,83.4 176.8,83.4 177.1,83.4 177.5,83.4
|
||||
177.6,83.4 177.9,83.5 178.1,83.5 178.4,83.6 178.6,83.7 178.8,83.8 179,83.9 179.2,84.1 179.4,84.3 179.5,84.5 179.7,84.6
|
||||
179.8,84.9 179.9,85.1 179.9,85.3 179.9,85.5 179.9,85.8 179.6,87.7 177.1,87.7 177,87.7 176.9,87.7 176.8,87.7 176.7,87.7
|
||||
176.6,87.7 176.5,87.7 176.4,87.7 176.3,87.8 176.2,87.8 176.1,87.8 176,87.8 175.9,87.8 175.8,87.8 175.7,87.9 175.6,87.9
|
||||
175.5,87.9 175.4,88 175.3,88 175.3,88.1 175.2,88.1 175.1,88.2 175,88.3 175,88.4 174.9,88.5 174.9,88.5 174.9,88.7 174.8,88.8
|
||||
174.8,89 174.8,89.1 174.9,89.3 174.9,89.3 175,89.5 175.1,89.5 175.2,89.6 175.3,89.7 175.5,89.7 175.6,89.8 175.8,89.8
|
||||
176,89.8 176.3,89.7 176.4,89.7 176.4,89.7 176.6,89.6 176.8,89.5 176.9,89.3 177.1,89.2 177.2,89.1 177.3,88.9 177.3,88.7
|
||||
177.4,88.6 177.5,88.4 177.5,88.3 177.5,88.1 177.6,88 177.6,87.9 177.6,87.8 177.5,87.8 177.5,87.7 177.4,87.7 177.3,87.7
|
||||
177.2,87.7 179.6,87.7 179.3,89.3 179.3,89.4 179.2,89.5 179.2,89.6 179.2,89.7 179.2,89.8 179.2,89.9 179.2,90 179.1,90.2
|
||||
179.1,90.3 179.1,90.4 179.1,90.5 179.1,90.7 179.1,90.8 179.1,90.9 179.1,91.1 177.3,91.1 177.3,90.4 177.2,90.4 177.2,90.4
|
||||
177.2,90.4 "/>
|
||||
<polyline class="st6" points="177.2,90.4 177.1,90.4 177,90.6 176.8,90.7 176.8,90.8 176.6,90.8 176.5,90.9 176.4,91 176.3,91
|
||||
176.1,91.1 176,91.1 175.8,91.2 175.7,91.2 175.5,91.2 175.3,91.2 175.2,91.2 175,91.2 174.8,91.2 174.7,91.2 174.4,91.2
|
||||
174.1,91.1 173.9,91 173.7,90.9 173.5,90.7 173.3,90.6 173.2,90.4 173.1,90.2 173,90 172.9,89.8 172.9,89.6 172.9,89.3
|
||||
172.8,89.1 172.9,88.9 172.9,88.7 172.9,88.5 173,88.3 173.1,88 173.3,87.7 173.5,87.5 173.7,87.3 173.9,87.1 174.2,86.9
|
||||
174.5,86.8 174.8,86.7 175.2,86.6 175.6,86.5 176,86.5 176.4,86.4 176.8,86.4 177.3,86.4 177.8,86.4 177.9,86.3 177.9,86.2
|
||||
177.9,86.1 177.9,86 177.9,85.9 177.9,85.8 177.8,85.7 177.8,85.5 177.7,85.4 "/>
|
||||
<polyline class="st6" points="177.7,85.4 177.6,85.3 177.4,85.2 177.2,85.1 177,85.1 176.8,85 176.7,85 176.3,85 176.2,85 176,85
|
||||
175.8,85 175.6,85.1 175.4,85.1 175.2,85.1 175,85.1 174.8,85.2 174.6,85.2 174.5,85.2 174.3,85.3 174.2,85.3 174,85.4
|
||||
174.1,84.9 174.4,83.8 174.5,83.8 174.6,83.7 174.7,83.7 174.9,83.7 175,83.6 175.2,83.6 175.3,83.6 175.5,83.5 175.7,83.5
|
||||
175.9,83.5 176.1,83.5 176.3,83.4 176.5,83.4 176.8,83.4 177.1,83.4 177.5,83.4 177.6,83.4 177.9,83.5 178.1,83.5 178.4,83.6
|
||||
178.6,83.7 178.8,83.8 179,83.9 179.2,84.1 179.4,84.3 179.5,84.5 179.7,84.6 179.8,84.9 179.9,85.1 179.9,85.3 179.9,85.5
|
||||
179.9,85.8 179.3,89.3 179.3,89.4 179.2,89.5 179.2,89.6 179.2,89.7 "/>
|
||||
<polyline class="st6" points="179.2,89.7 179.2,89.8 179.2,89.9 179.2,90 179.1,90.2 179.1,90.3 179.1,90.4 179.1,90.5
|
||||
179.1,90.7 179.1,90.8 179.1,90.9 179.1,91.1 177.3,91.1 177.3,90.4 177.2,90.4 177.2,90.4 177.2,90.4 "/>
|
||||
<polyline class="st6" points="177.5,87.8 177.5,87.7 177.4,87.7 177.3,87.7 177.2,87.7 177.1,87.7 177,87.7 176.9,87.7
|
||||
176.8,87.7 176.7,87.7 176.6,87.7 176.5,87.7 176.4,87.7 176.3,87.8 176.2,87.8 176.1,87.8 176,87.8 175.9,87.8 175.8,87.8
|
||||
175.7,87.9 175.6,87.9 175.5,87.9 175.4,88 175.3,88 175.3,88.1 175.2,88.1 175.1,88.2 175,88.3 175,88.4 174.9,88.5 174.9,88.5
|
||||
174.9,88.7 174.8,88.8 174.8,89 174.8,89.1 174.9,89.3 174.9,89.3 175,89.5 175.1,89.5 175.2,89.6 175.3,89.7 175.5,89.7
|
||||
175.6,89.8 175.8,89.8 176,89.8 176.3,89.7 176.4,89.7 176.4,89.7 176.6,89.6 176.8,89.5 176.9,89.3 177.1,89.2 177.2,89.1
|
||||
177.3,88.9 177.3,88.7 177.4,88.6 177.5,88.4 177.5,88.3 177.5,88.1 177.6,88 "/>
|
||||
<polyline class="st6" points="177.6,88 177.6,87.9 177.6,87.8 177.5,87.8 "/>
|
||||
<polygon class="st4" points="151.7,81.8 153.7,81.8 153.3,83.5 154.5,83.5 154.2,85.2 153,85.2 152.5,88.5 152.4,88.5 152.4,88.6
|
||||
152.4,88.8 152.4,88.9 152.4,89.1 152.5,89.2 152.5,89.3 152.6,89.3 152.7,89.4 152.8,89.4 152.9,89.4 153,89.4 153.3,89.4
|
||||
153.5,89.4 153.7,89.4 153.9,89.4 153.5,91.1 153.2,91.1 152.9,91.2 152.4,91.2 152,91.2 151.6,91.2 151.3,91.1 151,91
|
||||
150.8,90.9 150.6,90.8 150.5,90.6 150.4,90.4 150.3,90.2 150.3,90 150.3,89.8 150.3,89.5 150.3,89.2 150.4,88.9 151.5,82.8
|
||||
151.7,81.8 "/>
|
||||
<polygon class="st5" points="160.6,89.1 160.3,90.8 160.2,90.8 160.1,90.9 160,90.9 159.9,91 159.8,91 159.7,91 159.6,91.1
|
||||
159.4,91.1 159.3,91.1 159.1,91.1 158.9,91.2 158.7,91.2 158.5,91.2 158.3,91.2 158,91.2 157.5,91.2 157.3,91.2 157,91.1
|
||||
156.6,91.1 156.3,91 155.9,90.8 155.6,90.7 155.3,90.5 155.1,90.3 154.9,90 154.7,89.7 154.5,89.4 154.4,89.1 154.3,88.7
|
||||
154.2,88.3 154.2,87.8 154.2,87.3 154.2,87.1 154.3,86.9 154.4,86.5 154.5,86.1 154.6,85.7 154.8,85.3 155,85 155.2,84.7
|
||||
155.5,84.4 155.7,84.2 156,84 156.3,83.8 156.6,83.7 156.9,83.5 157.2,83.4 157.6,83.4 157.9,83.4 158.1,83.4 158.4,83.4
|
||||
158.8,83.4 159.2,83.5 159.5,83.7 159.9,83.8 160.1,84 160.4,84.2 160.6,84.5 160.8,84.8 160.8,84.9 157.7,84.9 157.5,84.9
|
||||
157.3,85 157.1,85.1 157,85.2 156.8,85.4 156.7,85.5 156.6,85.6 156.5,85.8 156.4,85.9 156.4,86.1 156.4,86.2 156.4,86.3
|
||||
156.4,86.4 156.5,86.4 159,86.4 159.1,86.3 159.1,86.2 159.1,86.1 159.1,86 159,85.8 159,85.7 158.9,85.6 158.9,85.5 158.8,85.4
|
||||
158.7,85.2 158.5,85.1 158.3,85 158.1,84.9 157.9,84.9 157.8,84.9 160.8,84.9 160.9,85.1 161,85.5 161.1,85.9 161.1,86.3
|
||||
161,86.8 160.9,87.3 160.8,87.9 156.2,87.9 156.1,87.9 156.1,88 156.1,88.1 156.1,88.3 156.1,88.4 156.1,88.5 156.2,88.7
|
||||
156.3,88.8 156.4,89 156.5,89.1 156.7,89.3 156.9,89.4 157.1,89.5 157.3,89.5 157.6,89.6 157.6,89.6 157.8,89.6 157.9,89.6
|
||||
158.1,89.6 158.3,89.6 158.4,89.6 158.6,89.6 158.8,89.6 159,89.6 159.2,89.5 159.4,89.5 159.6,89.4 159.7,89.4 159.9,89.3
|
||||
160.1,89.3 160.4,89.2 160.6,89.1 "/>
|
||||
<polyline class="st6" points="160.6,89.1 160.3,90.8 160.2,90.8 160.1,90.9 160,90.9 159.9,91 159.8,91 159.7,91 159.6,91.1
|
||||
159.4,91.1 159.3,91.1 159.1,91.1 158.9,91.2 158.7,91.2 158.5,91.2 158.3,91.2 158,91.2 157.5,91.2 157.3,91.2 157,91.1
|
||||
156.6,91.1 156.3,91 155.9,90.8 155.6,90.7 155.3,90.5 155.1,90.3 154.9,90 154.7,89.7 154.5,89.4 154.4,89.1 154.3,88.7
|
||||
154.2,88.3 154.2,87.8 154.2,87.3 154.2,87.1 154.3,86.9 154.4,86.5 154.5,86.1 154.6,85.7 154.8,85.3 155,85 155.2,84.7
|
||||
155.5,84.4 155.7,84.2 156,84 156.3,83.8 156.6,83.7 156.9,83.5 157.2,83.4 157.6,83.4 157.9,83.4 158.1,83.4 158.4,83.4
|
||||
158.8,83.4 159.2,83.5 159.5,83.7 159.9,83.8 160.1,84 160.4,84.2 160.6,84.5 "/>
|
||||
<polyline class="st6" points="160.6,84.5 160.8,84.8 160.9,85.1 161,85.5 161.1,85.9 161.1,86.3 161,86.8 160.9,87.3 160.8,87.9
|
||||
156.2,87.9 156.1,87.9 156.1,88 156.1,88.1 156.1,88.3 156.1,88.4 156.1,88.5 156.2,88.7 156.3,88.8 156.4,89 156.5,89.1
|
||||
156.7,89.3 156.9,89.4 157.1,89.5 157.3,89.5 157.6,89.6 157.6,89.6 157.8,89.6 157.9,89.6 158.1,89.6 158.3,89.6 158.4,89.6
|
||||
158.6,89.6 158.8,89.6 159,89.6 159.2,89.5 159.4,89.5 159.6,89.4 159.7,89.4 159.9,89.3 160.1,89.3 160.4,89.2 160.6,89.1 "/>
|
||||
<polyline class="st6" points="159,86.4 159.1,86.3 159.1,86.2 159.1,86.1 159.1,86 159,85.8 159,85.7 158.9,85.6 158.9,85.5
|
||||
158.8,85.4 158.7,85.2 158.5,85.1 158.3,85 158.1,84.9 157.9,84.9 157.7,84.9 157.5,84.9 157.3,85 157.1,85.1 157,85.2
|
||||
156.8,85.4 156.7,85.5 156.6,85.6 156.5,85.8 156.4,85.9 156.4,86.1 156.4,86.2 156.4,86.3 156.4,86.4 156.5,86.4 159,86.4 "/>
|
||||
<polygon class="st5" points="193.1,91 193.1,89.8 193.6,89.8 193.7,89.8 193.8,89.9 193.8,89.9 193.9,89.9 193.9,89.9 194,90
|
||||
194,90 194,90 194,90.1 194,90.2 194,90.2 194,90.3 194,90.4 193.8,90.4 193.8,90.3 193.8,90.3 193.9,90.3 193.9,90.2 193.9,90.2
|
||||
193.9,90.1 193.9,90.1 193.8,90 193.8,90 193.7,90 193.7,90 193.6,90 193.3,90 193.3,90.4 193.7,90.4 193.8,90.4 194,90.4
|
||||
193.9,90.4 193.9,90.4 193.8,90.5 193.8,90.5 194.1,91 193.9,91 193.6,90.5 193.3,90.5 193.3,91 193.1,91 "/>
|
||||
<polygon class="st5" points="193.5,91.3 193.6,91.3 193.7,91.3 193.8,91.3 193.8,91.3 193.9,91.2 194,91.2 194,91.2 194.1,91.1
|
||||
194.2,91.1 194.2,91 194.3,90.9 194.3,90.9 194.3,90.8 194.4,90.7 194.4,90.7 194.4,90.6 194.4,90.5 194.4,90.4 194.4,90.4
|
||||
194.4,90.3 194.4,90.2 194.4,90.1 194.3,90 194.3,90 194.3,89.9 194.2,89.9 194.2,89.8 194.1,89.7 194,89.7 194,89.6 193.9,89.6
|
||||
193.8,89.6 193.8,89.6 193.7,89.6 193.6,89.5 193.5,89.5 193.5,89.5 193.4,89.6 193.3,89.6 193.2,89.6 193.2,89.6 193.1,89.6
|
||||
193,89.7 193,89.7 192.9,89.8 192.9,89.9 192.8,89.9 192.8,90 192.7,90 192.7,90.1 192.7,90.2 192.7,90.3 192.7,90.4 192.7,90.5
|
||||
192.7,90.6 192.7,90.7 192.7,90.7 192.7,90.8 192.8,90.9 192.8,90.9 192.9,91 192.9,91.1 193,91.1 193,91.2 193.1,91.2
|
||||
193.2,91.2 193.2,91.3 193.3,91.3 193.4,91.3 193.5,91.3 193.5,91.3 193.5,91.2 193.5,91.2 193.4,91.2 193.3,91.2 193.2,91.2
|
||||
193.2,91.1 193.1,91.1 193,91 193,91 192.9,90.9 192.9,90.9 192.8,90.8 192.8,90.7 192.8,90.7 192.8,90.6 192.7,90.5 192.7,90.4
|
||||
192.8,90.3 192.8,90.2 192.8,90.1 192.8,90 192.9,90 192.9,89.9 193,89.9 193,89.8 193.1,89.8 193.2,89.7 193.2,89.7 193.3,89.6
|
||||
193.4,89.6 193.5,89.6 193.6,89.6 193.7,89.6 193.8,89.6 193.8,89.7 193.9,89.7 194,89.8 194,89.8 194.1,89.9 194.1,89.9
|
||||
194.2,90 194.2,90 194.3,90.1 194.3,90.2 194.3,90.3 194.3,90.4 194.3,90.4 194.3,90.5 194.3,90.6 194.3,90.7 194.3,90.7
|
||||
194.2,90.8 194.2,90.9 194.1,90.9 194.1,91 194,91 194,91.1 193.9,91.1 193.8,91.2 193.8,91.2 193.7,91.2 193.6,91.2 193.5,91.2
|
||||
193.5,91.3 "/>
|
||||
</g>
|
||||
</g>
|
||||
<polygon class="st7" points="24.1,63.5 106.3,63.5 106.3,112.2 24.1,112.2 24.1,63.5 "/>
|
||||
<g>
|
||||
<polygon class="st8" points="216.5,62.2 291.7,62.2 291.7,109.4 216.5,109.4 216.5,62.2 "/>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st9" d="M226.6,78.2c0.9-0.2,2.4-0.3,3.8-0.3c2.1,0,3.4,0.4,4.4,1.1c0.8,0.6,1.3,1.5,1.3,2.8c0,1.5-1,2.8-2.7,3.4v0
|
||||
c1.5,0.4,3.3,1.6,3.3,3.9c0,1.4-0.6,2.4-1.4,3.1c-1.1,1-3,1.5-5.6,1.5c-1.4,0-2.5-0.1-3.2-0.2V78.2z M228.7,84.6h1.9
|
||||
c2.2,0,3.5-1.1,3.5-2.6c0-1.8-1.4-2.6-3.6-2.6c-1,0-1.5,0.1-1.9,0.1V84.6z M228.7,92.1c0.4,0.1,1,0.1,1.8,0.1
|
||||
c2.2,0,4.2-0.8,4.2-3.1c0-2.1-1.9-3-4.2-3h-1.7V92.1z"/>
|
||||
<path class="st9" d="M242.2,88.7l-1.7,4.9h-2.2l5.5-15.7h2.5l5.5,15.7h-2.2l-1.7-4.9H242.2z M247.6,87.1l-1.6-4.5
|
||||
c-0.4-1-0.6-2-0.8-2.9h-0.1c-0.2,0.9-0.5,1.9-0.8,2.8l-1.6,4.5H247.6z"/>
|
||||
<path class="st9" d="M254.3,93.7V78h2.3l5.2,8c1.2,1.8,2.1,3.5,2.9,5.1l0,0c-0.2-2.1-0.2-4-0.2-6.5V78h2v15.7h-2.1l-5.1-8
|
||||
c-1.1-1.7-2.2-3.5-3-5.2l-0.1,0c0.1,2,0.2,3.9,0.2,6.5v6.7H254.3z"/>
|
||||
<path class="st9" d="M270.2,78h2.1v7.6h0.1c0.4-0.6,0.9-1.2,1.3-1.7l5-5.9h2.6l-5.9,6.7l6.3,9h-2.5l-5.3-7.7l-1.5,1.7v6h-2.1V78z
|
||||
"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st10" d="M100.1,15.7h9.9c5.3,0,7.3,2.7,7,6.7c-0.5,6.5-4.5,10.2-9.7,10.2h-2.6c-0.7,0-1.2,0.5-1.4,1.8l-1.1,7.5
|
||||
c-0.1,0.5-0.3,0.8-0.7,0.8h-6.2c-0.6,0-0.8-0.4-0.6-1.4l3.8-24C98.5,16.1,99,15.7,100.1,15.7z"/>
|
||||
<path class="st11" d="M143.2,15.2c3.3,0,6.4,1.8,6,6.3c-0.5,5.4-3.4,8.4-7.9,8.4h-4c-0.6,0-0.8,0.5-1,1.4l-0.8,4.9
|
||||
c-0.1,0.7-0.5,1.1-1.1,1.1h-3.7c-0.6,0-0.8-0.4-0.7-1.2l3.1-19.6c0.1-1,0.5-1.3,1.2-1.3H143.2L143.2,15.2z M137.1,25.7h3
|
||||
c1.9-0.1,3.1-1.4,3.3-3.7c0.1-1.5-0.9-2.5-2.5-2.5l-2.8,0L137.1,25.7L137.1,25.7z M159.2,35.8c0.3-0.3,0.7-0.5,0.6-0.1l-0.1,0.9
|
||||
c-0.1,0.5,0.1,0.7,0.6,0.7h3.3c0.6,0,0.8-0.2,1-1.1l2-12.7c0.1-0.6-0.1-0.9-0.5-0.9h-3.6c-0.3,0-0.5,0.2-0.6,0.7l-0.1,0.8
|
||||
c-0.1,0.4-0.3,0.5-0.4,0.1c-0.6-1.5-2.2-2.1-4.4-2.1c-5.1,0.1-8.5,3.9-8.8,8.9c-0.3,3.8,2.4,6.8,6,6.8
|
||||
C156.7,37.8,157.9,37,159.2,35.8L159.2,35.8z M156.5,33.9c-2.2,0-3.7-1.7-3.4-3.9c0.3-2.1,2.4-3.9,4.5-3.9c2.2,0,3.7,1.7,3.4,3.9
|
||||
C160.7,32.1,158.6,33.9,156.5,33.9L156.5,33.9z M173,22.6h-3.3c-0.7,0-1,0.5-0.7,1.1l4.1,12.1l-4.1,5.8c-0.3,0.5-0.1,0.9,0.4,0.9
|
||||
h3.7c0.6,0,0.8-0.1,1.1-0.5l12.7-18.2c0.4-0.6,0.2-1.1-0.4-1.2l-3.5,0c-0.6,0-0.9,0.2-1.2,0.7l-5.3,7.7l-2.4-7.7
|
||||
C174,22.9,173.6,22.6,173,22.6z"/>
|
||||
<path class="st10" d="M200.2,15.2c3.3,0,6.4,1.8,6,6.3c-0.5,5.4-3.4,8.4-7.9,8.4h-4c-0.6,0-0.8,0.5-1,1.4l-0.8,4.9
|
||||
c-0.1,0.7-0.5,1.1-1.1,1.1h-3.7c-0.6,0-0.8-0.4-0.7-1.2l3.1-19.6c0.1-1,0.5-1.3,1.2-1.3H200.2L200.2,15.2z M194.1,25.7h3
|
||||
c1.9-0.1,3.1-1.4,3.3-3.7c0.1-1.5-0.9-2.5-2.5-2.5l-2.8,0L194.1,25.7L194.1,25.7z M216.2,35.8c0.3-0.3,0.7-0.5,0.6-0.1l-0.1,0.9
|
||||
c-0.1,0.5,0.1,0.7,0.6,0.7h3.3c0.6,0,0.8-0.2,1-1.1l2-12.7c0.1-0.6-0.1-0.9-0.5-0.9h-3.6c-0.3,0-0.5,0.2-0.6,0.7l-0.1,0.8
|
||||
c-0.1,0.4-0.3,0.5-0.4,0.1c-0.6-1.5-2.2-2.1-4.4-2.1c-5.1,0.1-8.5,3.9-8.8,8.9c-0.3,3.8,2.4,6.8,6,6.8
|
||||
C213.7,37.8,214.9,37,216.2,35.8L216.2,35.8z M213.5,33.9c-2.2,0-3.7-1.7-3.4-3.9c0.3-2.1,2.4-3.9,4.5-3.9c2.2,0,3.7,1.7,3.4,3.9
|
||||
C217.7,32.1,215.6,33.9,213.5,33.9L213.5,33.9z M228.6,37.4h-3.8c-0.3,0-0.5-0.2-0.5-0.5l3.3-21.1c0-0.3,0.3-0.5,0.6-0.5h3.8
|
||||
c0.3,0,0.5,0.2,0.5,0.5l-3.3,21.1C229.2,37.2,228.9,37.4,228.6,37.4z"/>
|
||||
<path class="st11" d="M93.9,7.4h9.9c2.8,0,6.1,0.1,8.3,2c1.5,1.3,2.3,3.4,2.1,5.6c-0.6,7.6-5.1,11.8-11.2,11.8h-4.9
|
||||
c-0.8,0-1.4,0.6-1.6,2l-1.4,8.7c-0.1,0.6-0.3,0.9-0.8,0.9h-6.1c-0.7,0-0.9-0.5-0.7-1.6L91.9,9C92.1,7.9,92.7,7.4,93.9,7.4z"/>
|
||||
<path class="st12" d="M96.6,28.1l1.7-11c0.2-1,0.7-1.4,1.7-1.4h9.9c1.6,0,3,0.3,4,0.7c-1,6.7-5.4,10.5-11.1,10.5h-4.9
|
||||
C97.4,26.9,96.9,27.2,96.6,28.1z"/>
|
||||
</g>
|
||||
<g>
|
||||
<polygon class="st13" points="54.8,98.3 58.4,77.4 64.1,77.4 60.5,98.3 "/>
|
||||
<path class="st13" d="M81.2,77.9C80,77.5,78.3,77,76.1,77c-5.6,0-9.6,2.8-9.6,6.9c0,3,2.8,4.7,5,5.7c2.2,1,3,1.7,3,2.6
|
||||
c0,1.4-1.8,2-3.4,2c-2.3,0-3.5-0.3-5.4-1.1l-0.7-0.3l-0.8,4.7c1.3,0.6,3.8,1.1,6.3,1.1c6,0,9.9-2.8,9.9-7.2c0-2.4-1.5-4.2-4.8-5.7
|
||||
c-2-1-3.2-1.6-3.2-2.6c0-0.9,1-1.8,3.3-1.8c1.9,0,3.2,0.4,4.3,0.8l0.5,0.2L81.2,77.9z"/>
|
||||
<path class="st13" d="M95.8,77.4h-4.4c-1.4,0-2.4,0.4-3,1.7l-8.5,19.2h6c0,0,1-2.6,1.2-3.1c0.7,0,6.5,0,7.3,0
|
||||
c0.2,0.7,0.7,3.1,0.7,3.1h5.3L95.8,77.4z M88.7,90.9c0.5-1.2,2.3-5.9,2.3-5.9c0,0.1,0.5-1.2,0.8-2l0.4,1.8c0,0,1.1,5,1.3,6.1H88.7z
|
||||
"/>
|
||||
<path class="st13" d="M50,77.4l-5.6,14.3l-0.6-2.9c-1-3.3-4.3-7-7.9-8.8L41,98.3l6,0l9-20.9H50z"/>
|
||||
<path class="st14" d="M39.3,77.4h-9.2L30,77.8c7.1,1.7,11.9,5.9,13.8,11l-2-9.6C41.5,77.8,40.5,77.4,39.3,77.4"/>
|
||||
</g>
|
||||
<g>
|
||||
<line class="st15" x1="315.6" y1="29.5" x2="243.4" y2="29.5"/>
|
||||
<line class="st16" x1="4.6" y1="27" x2="4.6" y2="121.8"/>
|
||||
<line class="st16" x1="315.6" y1="27" x2="315.6" y2="121.8"/>
|
||||
<line class="st16" x1="3.6" y1="121.8" x2="315.6" y2="121.8"/>
|
||||
<line class="st15" x1="75.8" y1="29.5" x2="3.6" y2="29.5"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 33 KiB |
32
payment/gateway/paypal/settings.php
Normal file
32
payment/gateway/paypal/settings.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Settings for the PayPal payment gateway
|
||||
*
|
||||
* @package paygw_paypal
|
||||
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
if ($ADMIN->fulltree) {
|
||||
|
||||
$settings->add(new admin_setting_heading('paygw_paypal_settings', '', get_string('pluginname_desc', 'paygw_paypal')));
|
||||
|
||||
\core_payment\helper::add_common_gateway_settings($settings, 'paygw_paypal');
|
||||
}
|
4
payment/gateway/paypal/styles.css
Normal file
4
payment/gateway/paypal/styles.css
Normal file
@ -0,0 +1,4 @@
|
||||
.core_payment_gateways_modal .paypal .icon {
|
||||
height: 40px;
|
||||
width: auto;
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template paygw_paypal/paypal_button_placeholder
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Context variables required for this template:
|
||||
* none
|
||||
|
||||
Example context (json):
|
||||
{}
|
||||
|
||||
}}
|
||||
<div class="bg-pulse-grey rounded" style="width: 100%; height: 45px; margin-bottom: 14px;"></div>
|
||||
<div class="bg-pulse-grey rounded" style="width: 100%; height: 45px; margin-bottom: 14px;"></div>
|
||||
<div class="bg-pulse-grey" style="width: 110px; height: 16px; margin: 10px auto; position: relative; bottom: 3px;"></div>
|
29
payment/gateway/paypal/version.php
Normal file
29
payment/gateway/paypal/version.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Version information
|
||||
*
|
||||
* @package paygw_paypal
|
||||
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2021052500; // Requires this Moodle version.
|
||||
$plugin->component = 'paygw_paypal'; // Full name of the plugin (used for diagnostics).
|
62
payment/manage_account.php
Normal file
62
payment/manage_account.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Manage one payment accounts
|
||||
*
|
||||
* @package core_payment
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
$id = optional_param('id', 0, PARAM_INT);
|
||||
$delete = optional_param('delete', false, PARAM_BOOL);
|
||||
$restore = optional_param('restore', false, PARAM_BOOL);
|
||||
|
||||
$pageurl = new moodle_url('/payment/manage_account.php');
|
||||
admin_externalpage_setup('paymentaccounts', '', [], $pageurl);
|
||||
|
||||
$enabledplugins = \core\plugininfo\paygw::get_enabled_plugins();
|
||||
|
||||
$account = new \core_payment\account($id);
|
||||
require_capability('moodle/payment:manageaccounts', $account->get_context());
|
||||
|
||||
if ($delete && !$account->get('archived') && confirm_sesskey()) {
|
||||
\core_payment\helper::delete_payment_account($account);
|
||||
redirect(new moodle_url('/payment/accounts.php'));
|
||||
}
|
||||
if ($restore && $account->get('archived') && confirm_sesskey()) {
|
||||
\core_payment\helper::restore_payment_account($account);
|
||||
redirect(new moodle_url('/payment/accounts.php'));
|
||||
}
|
||||
|
||||
$PAGE->set_heading($id ? format_string($account->get('name')) : get_string('createaccount', 'payment'));
|
||||
|
||||
$form = new \core_payment\form\account($pageurl->out(false), ['persistent' => $account]);
|
||||
|
||||
if ($form->is_cancelled()) {
|
||||
redirect(new moodle_url('/payment/accounts.php'));
|
||||
} else if ($data = $form->get_data()) {
|
||||
\core_payment\helper::save_payment_account($data);
|
||||
redirect(new moodle_url('/payment/accounts.php'));
|
||||
}
|
||||
|
||||
echo $OUTPUT->header();
|
||||
$form->display();
|
||||
echo $OUTPUT->footer();
|
63
payment/manage_gateway.php
Normal file
63
payment/manage_gateway.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Manage one payment gateway
|
||||
*
|
||||
* @package core_payment
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
$id = optional_param('id', 0, PARAM_INT);
|
||||
$accountid = optional_param('accountid', 0, PARAM_INT);
|
||||
$gatewayname = optional_param('gateway', null, PARAM_COMPONENT);
|
||||
|
||||
$pageurl = new moodle_url('/payment/manage_gateway.php');
|
||||
admin_externalpage_setup('paymentaccounts', '', [], $pageurl);
|
||||
|
||||
$enabledplugins = \core\plugininfo\paygw::get_enabled_plugins();
|
||||
|
||||
if ($id) {
|
||||
$gateway = new \core_payment\account_gateway($id);
|
||||
$account = new \core_payment\account($gateway->get('accountid'));
|
||||
} else if ($accountid) {
|
||||
$account = new \core_payment\account($accountid);
|
||||
$gateway = $account->get_gateways()[$gatewayname] ?? null;
|
||||
}
|
||||
|
||||
if (empty($account) || empty($gateway)) {
|
||||
throw new moodle_exception('gatewaynotfound', 'payment');
|
||||
}
|
||||
require_capability('moodle/payment:manageaccounts', $account->get_context());
|
||||
|
||||
$PAGE->set_heading($id ? format_string($account->get('name')) : get_string('createaccount', 'payment'));
|
||||
|
||||
$form = new \core_payment\form\account_gateway($pageurl->out(false), ['persistent' => $gateway]);
|
||||
|
||||
if ($form->is_cancelled()) {
|
||||
redirect(new moodle_url('/payment/accounts.php'));
|
||||
} else if ($data = $form->get_data()) {
|
||||
\core_payment\helper::save_payment_gateway($data);
|
||||
redirect(new moodle_url('/payment/accounts.php'));
|
||||
}
|
||||
|
||||
echo $OUTPUT->header();
|
||||
$form->display();
|
||||
echo $OUTPUT->footer();
|
49
payment/templates/fee_breakdown.mustache
Normal file
49
payment/templates/fee_breakdown.mustache
Normal file
@ -0,0 +1,49 @@
|
||||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_payment/fee_breakdown_placeholder
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Context variables required for this template:
|
||||
* none
|
||||
|
||||
Example context (json):
|
||||
{}
|
||||
|
||||
}}
|
||||
<div class="core_payment_fee_breakdown">
|
||||
{{#surcharge}}
|
||||
{{# str }} labelvalue, core, {
|
||||
"label": {{# quote }}{{# str }} cost {{/ str }}{{/ quote }},
|
||||
"value": {{# quote }}{{# str }} feeincludesurcharge, core_payment, {
|
||||
"fee": "{{fee}}",
|
||||
"surcharge": {{surcharge}}
|
||||
} {{/ str }}{{/ quote }}
|
||||
} {{/ str }}
|
||||
{{/surcharge}}
|
||||
{{^surcharge}}
|
||||
{{# str }} labelvalue, core, {
|
||||
"label": {{# quote }}{{# str }} cost {{/ str }}{{/ quote }},
|
||||
"value": "{{fee}}"
|
||||
} {{/ str }}
|
||||
{{/surcharge}}
|
||||
</div>
|
51
payment/templates/gateway.mustache
Normal file
51
payment/templates/gateway.mustache
Normal file
@ -0,0 +1,51 @@
|
||||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_payment/gateway
|
||||
|
||||
This template will render the gateway option in the gateway selector modal.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Context variables required for this template:
|
||||
* shortname
|
||||
* name
|
||||
* description
|
||||
* surcharge
|
||||
* image
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"shortname": "paypal",
|
||||
"name": "PayPal",
|
||||
"description": "A description for PayPal.",
|
||||
"surcharge": "3"
|
||||
}
|
||||
|
||||
}}
|
||||
<div class="custom-control custom-radio {{shortname}}">
|
||||
<input class="custom-control-input" type="radio" name="payby" id="id-payby-{{uniqid}}-{{shortname}}" data-cost="{{cost}}" data-surcharge="{{surcharge}}" value="{{shortname}}" {{#checked}} checked="checked" {{/checked}} />
|
||||
<label class="custom-control-label bg-light border p-3 my-3" for="id-payby-{{uniqid}}-{{shortname}}">
|
||||
<p class="h3">{{name}}</p>
|
||||
<p class="content mb-2">{{description}}</p>
|
||||
{{#pix}} img, paygw_{{shortname}} {{/pix}}
|
||||
</label>
|
||||
</div>
|
55
payment/templates/gateways.mustache
Normal file
55
payment/templates/gateways.mustache
Normal file
@ -0,0 +1,55 @@
|
||||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_payment/gateways
|
||||
|
||||
This template will render the list of gateways in the gateway selector modal.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Context variables required for this template:
|
||||
* gateways
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"gateways" : [
|
||||
{
|
||||
"shortname": "paypal",
|
||||
"name": "PayPal",
|
||||
"description": "A description for PayPal.",
|
||||
"image": "../../../pix/help.svg"
|
||||
},
|
||||
{
|
||||
"shortname": "stripe",
|
||||
"name": "Stripe",
|
||||
"description": "A description for Stripe.",
|
||||
"image": "../../../pix/help.svg"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}}
|
||||
{{#gateways}}
|
||||
{{> core_payment/gateway }}
|
||||
{{/gateways}}
|
||||
{{^gateways}}
|
||||
<p>{{#str}}nogateway, core_payment{{/str}}</p>
|
||||
{{/gateways}}
|
42
payment/templates/gateways_modal.mustache
Normal file
42
payment/templates/gateways_modal.mustache
Normal file
@ -0,0 +1,42 @@
|
||||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_payment/gateways_modal
|
||||
|
||||
This template will render the gateway selector modal.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Context variables required for this template:
|
||||
* none
|
||||
|
||||
Example context (json):
|
||||
{}
|
||||
|
||||
}}
|
||||
<div class="core_payment_gateways_modal">
|
||||
<div data-region="gateways-container">
|
||||
{{> core_payment/gateways_placeholder }}
|
||||
</div>
|
||||
<div data-region="fee-breakdown-container">
|
||||
<div class="bg-pulse-grey" style="height: 22px; width: 90px"></div>
|
||||
</div>
|
||||
</div>
|
41
payment/templates/gateways_placeholder.mustache
Normal file
41
payment/templates/gateways_placeholder.mustache
Normal file
@ -0,0 +1,41 @@
|
||||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_payment/gateways_placeholder
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Context variables required for this template:
|
||||
* none
|
||||
|
||||
Example context (json):
|
||||
{}
|
||||
|
||||
}}
|
||||
<div class="custom-control custom-radio">
|
||||
<input class="custom-control-input" type="radio" disabled />
|
||||
<label class="custom-control-label bg-light border p-3 my-3 w-100">
|
||||
<div class="bg-pulse-grey mb-2" style="height: 31px; width: 18%"></div>
|
||||
<div class="bg-pulse-grey mb-1" style="height: 20px; width: 95%"></div>
|
||||
<div class="bg-pulse-grey mb-2" style="height: 20px; width: 25%"></div>
|
||||
<div class="bg-pulse-grey" style="height: 40px; width: 30%"></div>
|
||||
</label>
|
||||
</div>
|
45
payment/templates/modal_gateways.mustache
Normal file
45
payment/templates/modal_gateways.mustache
Normal file
@ -0,0 +1,45 @@
|
||||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_payment/modal_gateways
|
||||
|
||||
Moodle modal template with save and cancel buttons.
|
||||
|
||||
The purpose of this template is to render a modal.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Context variables required for this template:
|
||||
* title A cleaned string (use clean_text()) to display.
|
||||
* body HTML content for the boday
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"title": "Example gateways modal",
|
||||
"body": "Some example content for the body"
|
||||
}
|
||||
}}
|
||||
{{< core/modal }}
|
||||
{{$footer}}
|
||||
<button type="button" class="btn btn-primary" data-action="proceed">{{#str}} proceed {{/str}}</button>
|
||||
<button type="button" class="btn btn-secondary" data-action="cancel">{{#str}} cancel {{/str}}</button>
|
||||
{{/footer}}
|
||||
{{/ core/modal }}
|
84
payment/tests/behat/accounts.feature
Normal file
84
payment/tests/behat/accounts.feature
Normal file
@ -0,0 +1,84 @@
|
||||
@core @core_payment
|
||||
Feature: Manage payment accounts
|
||||
|
||||
@javascript
|
||||
Scenario: Creating and editing payment account
|
||||
When I log in as "admin"
|
||||
And I navigate to "Payments > Payment accounts" in site administration
|
||||
And I follow "Manage payment gateways"
|
||||
Then "Australian Dollar" "text" should exist in the "PayPal" "table_row"
|
||||
And I follow "Payment accounts"
|
||||
And I press "Create payment account"
|
||||
And I set the field "Account name" to "TestAccount"
|
||||
And I press "Save changes"
|
||||
And I should see "PayPal" in the "TestAccount" "table_row"
|
||||
And I open the action menu in "TestAccount" "table_row"
|
||||
And I choose "Edit" in the open action menu
|
||||
And I set the field "Account name" to "NewName"
|
||||
And I press "Save changes"
|
||||
And I should see "PayPal" in the "NewName" "table_row"
|
||||
And I should not see "TestAccount"
|
||||
And I log out
|
||||
|
||||
@javascript
|
||||
Scenario: Configuring gateways on payment accounts
|
||||
Given the following "core_payment > payment accounts" exist:
|
||||
| name |
|
||||
| Account1 |
|
||||
| Account2 |
|
||||
When I log in as "admin"
|
||||
And I navigate to "Payments > Payment accounts" in site administration
|
||||
Then I should see "Not available" in the "Account1" "table_row"
|
||||
And I click on "PayPal" "link" in the "Account1" "table_row"
|
||||
And I set the field "Brand name" to "Test paypal"
|
||||
And I set the following fields to these values:
|
||||
| Brand name | Test paypal |
|
||||
| Client ID | Test |
|
||||
| Secret | Test |
|
||||
| Enable | 1 |
|
||||
And I press "Save changes"
|
||||
And I should see "PayPal" in the "Account1" "table_row"
|
||||
And I should not see "Not available" in the "Account1" "table_row"
|
||||
And I log out
|
||||
|
||||
@javascript
|
||||
Scenario: Deleting payment accounts
|
||||
Given the following "core_payment > payment accounts" exist:
|
||||
| name |
|
||||
| Account1 |
|
||||
| Account2 |
|
||||
When I log in as "admin"
|
||||
And I navigate to "Payments > Payment accounts" in site administration
|
||||
And I open the action menu in "Account1" "table_row"
|
||||
And I choose "Delete or archive" in the open action menu
|
||||
And I click on "Yes" "button" in the "Confirmation" "dialogue"
|
||||
Then I should not see "Account1"
|
||||
And I should see "Account2"
|
||||
And I log out
|
||||
|
||||
@javascript
|
||||
Scenario: Archiving and restoring accounts
|
||||
Given the following "users" exist:
|
||||
| username |
|
||||
| user1 |
|
||||
And the following "core_payment > payment accounts" exist:
|
||||
| name |
|
||||
| Account1 |
|
||||
| Account2 |
|
||||
And the following "core_payment > payments" exist:
|
||||
| account | component | amount | user |
|
||||
| Account1 | test | 10 | user1 |
|
||||
| Account1 | test | 15 | user1 |
|
||||
When I log in as "admin"
|
||||
And I navigate to "Payments > Payment accounts" in site administration
|
||||
And I open the action menu in "Account1" "table_row"
|
||||
And I choose "Delete or archive" in the open action menu
|
||||
And I click on "Yes" "button" in the "Confirmation" "dialogue"
|
||||
Then I should not see "Account1"
|
||||
And I should see "Account2"
|
||||
And I follow "Show archived"
|
||||
And I should see "Archived" in the "Account1" "table_row"
|
||||
And I open the action menu in "Account1" "table_row"
|
||||
And I choose "Restore" in the open action menu
|
||||
And I should not see "Archived" in the "Account1" "table_row"
|
||||
And I log out
|
72
payment/tests/generator/behat_core_payment_generator.php
Normal file
72
payment/tests/generator/behat_core_payment_generator.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Behat data generator for core_payment.
|
||||
*
|
||||
* @package core_payment
|
||||
* @category test
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Behat data generator for core_payment.
|
||||
*
|
||||
* @package core_payment
|
||||
* @category test
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_core_payment_generator extends behat_generator_base {
|
||||
|
||||
/**
|
||||
* Get a list of the entities that can be created.
|
||||
*
|
||||
* @return array entity name => information about how to generate.
|
||||
*/
|
||||
protected function get_creatable_entities(): array {
|
||||
return [
|
||||
'payment accounts' => [
|
||||
'singular' => 'payment account',
|
||||
'datagenerator' => 'payment_account',
|
||||
'required' => ['name'],
|
||||
],
|
||||
'payments' => [
|
||||
'singular' => 'payment',
|
||||
'datagenerator' => 'payment',
|
||||
'required' => ['account', 'amount', 'user'],
|
||||
'switchids' => ['account' => 'accountid', 'user' => 'userid'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the id of a account from its name.
|
||||
*
|
||||
* @param string $accountname
|
||||
* @return int corresponding id.
|
||||
*/
|
||||
protected function get_account_id(string $accountname): int {
|
||||
global $DB;
|
||||
|
||||
if (!$id = $DB->get_field('payment_accounts', 'id', ['name' => $accountname])) {
|
||||
throw new Exception('There is no account with name "' . $accountname . '".');
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
}
|
82
payment/tests/generator/lib.php
Normal file
82
payment/tests/generator/lib.php
Normal file
@ -0,0 +1,82 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Quiz module test data generator class
|
||||
*
|
||||
* @package core_payment
|
||||
* @category test
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_payment_generator extends component_generator_base {
|
||||
|
||||
/** @var int */
|
||||
protected $accountcounter = 0;
|
||||
|
||||
/**
|
||||
* Create a payment account
|
||||
*
|
||||
* @param array $data account data (name, idnumber, enabled) and additionally field 'gateways' that can include
|
||||
* a list of gateways that should be mock-enabled for this account.
|
||||
*/
|
||||
public function create_payment_account(array $data = []): \core_payment\account {
|
||||
$this->accountcounter++;
|
||||
$gateways = [];
|
||||
if (!empty($data['gateways'])) {
|
||||
$gateways = preg_split('/,/', $data['gateways']);
|
||||
}
|
||||
unset($data['gateways']);
|
||||
$account = \core_payment\helper::save_payment_account(
|
||||
(object)($data + ['name' => 'Test '.$this->accountcounter, 'idnumber' => '', 'enabled' => 1]));
|
||||
foreach ($gateways as $gateway) {
|
||||
\core_payment\helper::save_payment_gateway(
|
||||
(object)['accountid' => $account->get('id'), 'gateway' => $gateway, 'enabled' => 1]);
|
||||
}
|
||||
return $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a payment account
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
public function create_payment(array $data): int {
|
||||
global $DB;
|
||||
if (empty($data['accountid']) || !\core_payment\account::get_record(['id' => $data['accountid']])) {
|
||||
throw new coding_exception('Account id is not specified or does not exist');
|
||||
}
|
||||
|
||||
if (empty($data['amount'])) {
|
||||
throw new coding_exception('Amount must be specified');
|
||||
}
|
||||
|
||||
$gateways = \core\plugininfo\paygw::get_enabled_plugins();
|
||||
if (empty($data['gateway'])) {
|
||||
$data['gateway'] = reset($gateways);
|
||||
}
|
||||
|
||||
$id = $DB->insert_record('payments', $data +
|
||||
[
|
||||
'component' => 'testcomponent',
|
||||
'paymentarea' => 'teatarea',
|
||||
'itemid' => 0,
|
||||
'currency' => 'AUD',
|
||||
]);
|
||||
return $id;
|
||||
}
|
||||
|
||||
}
|
72
payment/tests/generator_test.php
Normal file
72
payment/tests/generator_test.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Testing generator in payments API
|
||||
*
|
||||
* @package core_payment
|
||||
* @category test
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_payment;
|
||||
|
||||
/**
|
||||
* Testing generator in payments API
|
||||
*
|
||||
* @package core_payment
|
||||
* @category test
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class helper_testcase extends \advanced_testcase {
|
||||
|
||||
public function test_create_account() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
/** @var \core_payment_generator $generator */
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_payment');
|
||||
$this->assertTrue($generator instanceof \core_payment_generator);
|
||||
|
||||
$account1 = $generator->create_payment_account();
|
||||
$account2 = $generator->create_payment_account(['name' => 'My name', 'gateways' => 'paypal']);
|
||||
|
||||
$record1 = $DB->get_record('payment_accounts', ['id' => $account1->get('id')]);
|
||||
$record2 = $DB->get_record('payment_accounts', ['id' => $account2->get('id')]);
|
||||
|
||||
$this->assertEquals(1, $record1->enabled);
|
||||
$this->assertEquals('My name', $record2->name);
|
||||
|
||||
// First account does not have gateways configurations.
|
||||
$this->assertEmpty($DB->get_records('payment_gateways', ['accountid' => $account1->get('id')]));
|
||||
// Second account has.
|
||||
$this->assertCount(1, $DB->get_records('payment_gateways', ['accountid' => $account2->get('id')]));
|
||||
}
|
||||
|
||||
public function test_create_payment() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
/** @var \core_payment_generator $generator */
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_payment');
|
||||
$account = $generator->create_payment_account(['gateways' => 'paypal']);
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
|
||||
$paymentid = $generator->create_payment(['accountid' => $account->get('id'), 'amount' => 10, 'userid' => $user->id]);
|
||||
|
||||
$this->assertEquals('testcomponent', $DB->get_field('payments', 'component', ['id' => $paymentid]));
|
||||
}
|
||||
}
|
188
payment/tests/helper_test.php
Normal file
188
payment/tests/helper_test.php
Normal file
@ -0,0 +1,188 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Testing helper class methods in payments API
|
||||
*
|
||||
* @package core_payment
|
||||
* @category test
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_payment;
|
||||
|
||||
use advanced_testcase;
|
||||
use core\plugininfo\paygw;
|
||||
|
||||
/**
|
||||
* Testing helper class methods in payments API
|
||||
*
|
||||
* @package core_payment
|
||||
* @category test
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class accounts_testcase extends advanced_testcase {
|
||||
|
||||
protected function enable_paypal_gateway(): bool {
|
||||
if (!array_key_exists('paypal', \core_component::get_plugin_list('paygw'))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function test_create_account() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$account = helper::save_payment_account((object)['name' => 'Test 1', 'idnumber' => '']);
|
||||
$this->assertNotEmpty($account->get('id'));
|
||||
$this->assertEquals('Test 1', $DB->get_field('payment_accounts', 'name', ['id' => $account->get('id')]));
|
||||
}
|
||||
|
||||
public function test_update_account_details() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$account = helper::save_payment_account((object)['name' => 'Test 1', 'idnumber' => '']);
|
||||
$record = $account->to_record();
|
||||
$record->name = 'Edited name';
|
||||
$editedaccount = helper::save_payment_account($record);
|
||||
$this->assertEquals($account->get('id'), $editedaccount->get('id'));
|
||||
$this->assertEquals('Edited name', $DB->get_field('payment_accounts', 'name', ['id' => $account->get('id')]));
|
||||
}
|
||||
|
||||
public function test_update_account_gateways() {
|
||||
global $DB;
|
||||
if (!$this->enable_paypal_gateway()) {
|
||||
$this->markTestSkipped('Paypal payment gateway plugin not found');
|
||||
}
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
$account = helper::save_payment_account((object)['name' => 'Test 1', 'idnumber' => '']);
|
||||
$gateway = helper::save_payment_gateway(
|
||||
(object)['accountid' => $account->get('id'), 'gateway' => 'paypal', 'config' => 'T1']);
|
||||
$this->assertNotEmpty($gateway->get('id'));
|
||||
$this->assertEquals('T1', $DB->get_field('payment_gateways', 'config', ['id' => $gateway->get('id')]));
|
||||
|
||||
// Update by id.
|
||||
$editedgateway = helper::save_payment_gateway(
|
||||
(object)['id' => $gateway->get('id'), 'accountid' => $account->get('id'), 'gateway' => 'paypal', 'config' => 'T2']);
|
||||
$this->assertEquals($gateway->get('id'), $editedgateway->get('id'));
|
||||
$this->assertEquals('T2', $DB->get_field('payment_gateways', 'config', ['id' => $gateway->get('id')]));
|
||||
|
||||
// Update by account/gateway.
|
||||
$editedgateway = helper::save_payment_gateway(
|
||||
(object)['accountid' => $account->get('id'), 'gateway' => 'paypal', 'config' => 'T3']);
|
||||
$this->assertEquals($gateway->get('id'), $editedgateway->get('id'));
|
||||
$this->assertEquals('T3', $DB->get_field('payment_gateways', 'config', ['id' => $gateway->get('id')]));
|
||||
}
|
||||
|
||||
public function test_delete_account() {
|
||||
global $DB;
|
||||
if (!$this->enable_paypal_gateway()) {
|
||||
$this->markTestSkipped('Paypal payment gateway plugin not found');
|
||||
}
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Delete account without payments, it will be deleted, gateways will also be deleted.
|
||||
$account = helper::save_payment_account((object)['name' => 'Test 1', 'idnumber' => '']);
|
||||
$gateway = helper::save_payment_gateway(
|
||||
(object)['accountid' => $account->get('id'), 'gateway' => 'paypal', 'config' => 'T1']);
|
||||
|
||||
helper::delete_payment_account(account::get_record(['id' => $account->get('id')]));
|
||||
$this->assertEmpty($DB->get_records('payment_accounts', ['id' => $account->get('id')]));
|
||||
$this->assertEmpty($DB->get_records('payment_gateways', ['id' => $gateway->get('id')]));
|
||||
}
|
||||
|
||||
public function test_archive_restore_account() {
|
||||
global $DB, $USER;
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Delete account with payments - it will be archived.
|
||||
$this->setAdminUser();
|
||||
$account = helper::save_payment_account((object)['name' => 'Test 1', 'idnumber' => '']);
|
||||
$DB->insert_record('payments', [
|
||||
'accountid' => $account->get('id'),
|
||||
'component' => 'test',
|
||||
'paymentarea' => 'test',
|
||||
'itemid' => 1,
|
||||
'userid' => $USER->id,
|
||||
]);
|
||||
helper::delete_payment_account(account::get_record(['id' => $account->get('id')]));
|
||||
$this->assertEquals(1, $DB->get_field('payment_accounts', 'archived', ['id' => $account->get('id')]));
|
||||
|
||||
// Restore account.
|
||||
helper::restore_payment_account(account::get_record(['id' => $account->get('id')]));
|
||||
$this->assertEquals(0, $DB->get_field('payment_accounts', 'archived', ['id' => $account->get('id')]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider for format_cost test
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_rounded_cost_provider(): array {
|
||||
return [
|
||||
'IRR 0 surcharge' => [5.345, 'IRR', 0, 5],
|
||||
'IRR 12% surcharge' => [5.345, 'IRR', 12, 6],
|
||||
'USD 0 surcharge' => [5.345, 'USD', 0, 5.34],
|
||||
'USD 1% surcharge' => [5.345, 'USD', 1, 5.4],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider for test_get_cost_as_string
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
public function get_cost_as_string_provider(): array {
|
||||
return [
|
||||
'IRR 0 surcharge' => [5.345, 'IRR', 0, 'IRR'."\xc2\xa0".'5'],
|
||||
'IRR 12% surcharge' => [5.345, 'IRR', 12, 'IRR'."\xc2\xa0".'6'],
|
||||
'USD 0 surcharge' => [5.345, 'USD', 0, 'USD'."\xc2\xa0".'5.34'],
|
||||
'USD 1% surcharge' => [5.345, 'USD', 1, 'USD'."\xc2\xa0".'5.40'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for test_format_cost function
|
||||
*
|
||||
* @dataProvider get_rounded_cost_provider
|
||||
* @param float $amount
|
||||
* @param string $currency
|
||||
* @param float $surcharge
|
||||
* @param string $expected
|
||||
*/
|
||||
public function test_get_rounded_cost(float $amount, string $currency, float $surcharge, string $expected) {
|
||||
$this->assertEquals($expected, helper::get_rounded_cost($amount, $currency, $surcharge));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for get_cost_as_string function
|
||||
*
|
||||
* @dataProvider get_cost_as_string_provider
|
||||
* @param float $amount
|
||||
* @param string $currency
|
||||
* @param float $surcharge
|
||||
* @param string $expected
|
||||
*/
|
||||
public function test_get_cost_as_string(float $amount, string $currency, float $surcharge, string $expected) {
|
||||
$this->assertEquals($expected, helper::get_cost_as_string($amount, $currency, $surcharge));
|
||||
}
|
||||
}
|
@ -2721,3 +2721,7 @@ $picker-emojis-per-row: 7 !default;
|
||||
}
|
||||
}
|
||||
}
|
||||
.core_payment_gateways_modal .custom-control-label::before,
|
||||
.core_payment_gateways_modal .custom-control-label::after {
|
||||
top: 45%;
|
||||
}
|
||||
|
@ -11870,6 +11870,10 @@ input[disabled] {
|
||||
border-style: solid;
|
||||
border-width: 0.125rem; }
|
||||
|
||||
.core_payment_gateways_modal .custom-control-label::before,
|
||||
.core_payment_gateways_modal .custom-control-label::after {
|
||||
top: 45%; }
|
||||
|
||||
.icon {
|
||||
font-size: 16px;
|
||||
width: 16px;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user